L'opération pourrait déstabiliser l'exécution?
J'ai un peu de mal à comprendre quel est le problème ici. J'ai un peu de code qui extrait les enregistrements d'une base de données en utilisant LINQ et les place dans un objet qui est moulé dans une interface. Cela ressemble un peu à ceci:
public IEnumerable<ISomeObject> query()
{
return from a in dc.SomeTable
select new SomeObject
{
//Assign various members here
} as ISomeObject;
}
Quand je teste ceci, je mets le IEnumerable retourné dans une variable appelée results et exécute cette ligne:
Assert.AreEqual(EXPECTED_COUNT, results.Count());
Quand ceci est exécuté, j'obtiens un système.Sécurité.VerificationException: "L'opération pourrait déstabiliser l'exécution."
Je j'ai trouvé la solution ici , qui est la suivante:
var results = from a in dc.SomeTable
select new SomeObject
{
//Assign various members here
} as ISomeTable;
return results.OfType<ISomeObject>();
Cela fonctionne, mais j'ai du mal à comprendre ce qui se passe ici. Pourquoi ai-je l'exception, en premier lieu, et comment les lignes de code ci-dessus résoudre ce problème? La documentation MSDN semble suggérer qu'il s'agit d'un problème de sécurité de type, mais je ne vois pas où le code précédent était dangereux.
Mise à jour Un peu plus d'information j'ai trouvé. Le premier exemple fonctionne si je fais le type de retour IQueryable. Cela jette un peu plus de lumière sur ce que allait mal, mais je suis toujours confus au sujet du pourquoi . Pourquoi le compilateur ne m'a-t-il pas forcé à lancer IEnumerable dans un IQueryable?
10 réponses
Je crois que c'est une question de covariance ou de contravariance comme l'a noté ce post du forum.
Voir Covariance et Contravariance en C#, deuxième partie: Array Covariance et le reste de la série Covariance et Contravariance sur le blog D'Eric Lippert.
Bien qu'il traite des tableaux dans l'article que j'ai lié, je crois qu'un problème similaire se présente ici. Avec votre premier exemple, vous renvoyez un IEnumerable
qui pourrait contenir des objets qui implémentez une interface qui est plus grande que ISomeTable
(c'est - à-dire-vous pouvez mettre une tortue dans un animal IEnumerable quand ce IEnumerable ne peut contenir que des girafes). Je pense que la raison pour laquelle cela fonctionne lorsque vous retournez IQueryable
est parce que c'est plus grand / plus large que tout ce que vous pourriez retourner, donc vous êtes assuré que ce que vous retournez sera capable de gérer (?).
Dans le deuxième exemple, OfType s'assure que ce qui est retourné est un objet qui stocke tous les informations nécessaires pour retourner uniquement les éléments qui peuvent être jetés à la girafe.
Je suis sûr que cela a quelque chose à voir avec les problèmes de sécurité de type décrits ci-dessus, mais comme le dit Eric Lippert les fonctions D'ordre supérieur me blessent le cerveau et j'ai du mal à exprimer précisément pourquoi il s'agit d'un problème co/contravariant.
J'ai trouvé cette entrée en cherchant ma propre solution pour "l'opération pourrait déstabiliser l'exécution". Bien que le Conseil de covariance/contre-variance ci-dessus semble très intéressant, j'ai finalement trouvé que j'obtenais le même message d'erreur en exécutant mes tests unitaires avec la couverture de code activée et L'ensemble d'attributs D'assemblage AllowPartiallyTrustedCallers.
La suppression de L'attribut AllowPartiallyTrustedCallers a provoqué le bon fonctionnement de mes tests. je pourrais également désactiver la couverture de code pour faire courir mais ce n'était pas une solution acceptable.
Espérons que cela aide quelqu'un d'autre qui se rend à cette page en essayant de trouver une solution à ce problème.
Juste une supposition, mais l'opérateur as peut renvoyer un null-donc cela peut avoir à voir avec l'implémentation réelle du code new SomeObject { ... }
, puisque c'est du sucre syntaxique. Les filtres return results.OfType<ISomeTable>();
basés sur le type, de sorte que l'instruction return de votre méthode ne retournera que ce type (assurant la sécurité du type). J'ai rencontré un problème similaire avec le retour des types génériques.
P.S. j'adore l'opération " pourrait déstabiliser l'exécution." exception. C'est presque comme le " vous pourriez faire sauter l'internet" exception.
Je suis tombé sur cette erreur avec un code similaire;
IEnumerable<Table> records = (from t in db.Tables
where t.Id.Equals(1)
select t).ToList();
CE code apparemment inoffensif faisait partie d'une méthode UserControl appelée à partir d'une Page. Pas de problème dans un environnement de développement. NET4, cependant, lorsque le site a été précompilé et déployé sur le serveur sur. NET3. 5, j'ai eu cette erreur.
Je soupçonne que cela a quelque chose à voir avec le fait que le contrôle était compilé dans une DLL séparée combinée avec les changements de sécurité entre les frameworks comme décrit dans ce blog de sécurité. net
Ma solution: exécutez le site en direct sur. NET4
Est-ce qu'il échoue toujours si vous changez ceci:
select new SomeObject { ... } as ISomeTable;
À ceci:
select (ISomeTable) new SomeObject { ... };
?
Si oui (comme je vois que vous avez confirmé), peut-être que cela a à voir avec le fait qu'une implémentation d'interface pourrait être une classe ou une structure? Le problème apparaît-il toujours si vous convertissez une classe abstraite plutôt qu'une interface?
J'ai trouvé que OfType avait des effets secondaires désagréables lors de l'utilisation de linq à sql. Par exemple, les parties de linq qui ont été précédemment évaluées après l'exécution de la requête sur la base de données ont été traduites en SQL. Cela a échoué car ces sections n'avaient pas D'équivalent SQL. J'ai fini de l'utiliser .Fonte à la place qui semble résoudre le problème.
Dans mon cas, j'avais déclaré à tort la propriété Storage dans L'attribut Column d'une classe Linq2SQL
[Column(Storage = "_Alias", DbType = "NVarChar(50)")]
public string UserAlias
, j'ai eu le même problème, mais avec l'héritage J'ai défini une classe dans l'assemblage A et une sous classe dans L'assemblage B après avoir ajouté l'attribut ci-dessous à l'assemblage A, Problème résolu:
[assembly: SecurityRules(SecurityRuleSet.Level1, SkipVerificationInFullTrust = true)]
J'ai rencontré cette erreur en utilisant le " Dynamic Data access framework "passive library . La source de l'erreur était la ligne 100 dans DynamicDatabase.cs fichier.
databaseDetectors = (databaseDetectors ?? Enumerable.Empty<DatabaseDetector>()).DefaultIfEmpty(new DatabaseDetector());
J'ai changé cette ligne de code en:
databaseDetectors = (databaseDetectors ?? Enumerable.Empty<DatabaseDetector>()).DefaultIfEmpty(new DatabaseDetector()).OfType<IDatabaseDetector>();
Cela a résolu le problème. Je suis allé de l'avant et forked le projet et soumis le changement à l'auteur original.
Merci, Jason Baker, d'avoir souligné la solution dans votre question initiale.
Sur une note de côté, l'original la bibliothèque fonctionnait bien sur ma machine locale et sur un VPS Rackspace, mais quand j'ai poussé le même code dans un environnement d'hébergement partagé (les Sites Cloud de GoDaddy et Rackspace), j'ai commencé à obtenir l'erreur" opération pourrait déstabiliser l'exécution".
Je suppose que Linq to Sql peut ne pas prendre en charge le casting lors de la traduction en instruction sql.