web-dev-qa-db-fra.com

Opération pourrait déstabiliser le runtime?

J'ai un peu de mal à comprendre le problème. J'ai un peu de code qui extrait des enregistrements d'une base de données à l'aide de LINQ et les met dans un objet qui est converti 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;
}

Lorsque je teste cela, je mets le IEnumerable renvoyé dans une variable appelée result et je lance cette ligne:

Assert.AreEqual(EXPECTED_COUNT, results.Count());

Lorsque cela est exécuté, j'obtiens une exception System.Security.VerificationException: "L'opération pourrait déstabiliser l'exécution."

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 eu l'exception en premier lieu et comment les lignes de code ci-dessus l'ont-elles corrigée? La documentation MSDN semble suggérer qu'il s'agit d'un problème de sécurité du type, mais je ne vois pas où le code précédent était dangereux pour le type.

UPDATE Un peu plus d'informations que j'ai découvertes. Le premier exemple fonctionne si je rends le type de retour IQueryable. Cela jette un peu plus de lumière sur quoi n'allait pas bien, mais je ne comprends toujours pas le pourquoi. Pourquoi le compilateur ne m'a-t-il pas obligé de convertir l'IEnumerable en un IQueryable?

37
Jason Baker

Je crois que c’est un problème de covariance ou de contravariance, comme indiqué par cet article 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 de Eric Lippert.

Bien qu'il traite de tableaux dans l'article que j'ai lié, je crois qu'un problème similaire se pose ici. Avec votre premier exemple, vous renvoyez une IEnumerable pouvant contenir des objets implémentant une interface plus grandeque ISomeTable (c'est-à-dire que vous pouvez placer une tortue dans un animal IEnumerable lorsque ce dernier ne peut contenir que des girafes). Je pense que la raison pour laquelle cela fonctionne lorsque vous retournez IQueryable est que c’est plus grand/plus large _ que tout ce que vous pouvez retourner, vous avez donc la garantie que vous pourrez gérer ce que vous retournez (?).

Dans le deuxième exemple, OfType s'assure que ce qui est renvoyé est un objet qui stocke toutes les informations nécessaires pour renvoyer uniquement les éléments pouvant être convertis en Giraffe.

Je suis presque 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/ Fonctions d'ordre supérieur Hurt My Brain et j'ai du mal à expliquer précisément pourquoi il s'agit d'un problème co/contravariant.

19
Grant Wagner

J'ai trouvé cette entrée en cherchant ma propre solution pour "l'opération pourrait déstabiliser l'exécution". Alors que le conseil de covariance/contre-variance ci-dessus semble très intéressant, j'ai finalement constaté que je reçois le même message d'erreur en exécutant mes tests unitaires avec la couverture de code activée et l'ensemble d'attributs AllowPartiallyTrustedCallers. 

La suppression de l'attribut AllowPartiallyTrustedCallers a entraîné le bon déroulement de mes tests. Je pourrais aussi désactiver la couverture de code pour les faire fonctionner, mais ce n'était pas une solution acceptable.

J'espère que cela aidera quelqu'un d'autre qui se rend sur cette page en essayant de trouver une solution à ce problème.

14
Ira Miller

Juste une conjecture, mais l'opérateur as peut retourner un null - il peut donc avoir un rapport avec l'implémentation réelle du code new SomeObject { ... }, puisqu'il s'agit d'un sucre syntaxique. Les filtres return results.OfType<ISomeTable>(); étant basés sur le type, l'instruction return de votre méthode ne renverra que ce type (garantissant 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 qui pourrait déstabiliser le temps d'exécution. exception. C'est presque comme l'exception "Vous pourriez faire exploser Internet".

5
Zachary Yates

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 était pré-compilé et déployé sur le serveur sous .NET3.5, j'ai eu cette erreur.

Je suppose que cela a quelque chose à voir avec le fait que le contrôle était compilé dans un DLL séparé, associé aux modifications de sécurité entre les frameworks décrites dans ce blog de sécurité .NET

Ma solution: exécuter le site en direct sur .NET4

2
Red Taz

J'ai eu le même problème, mais avec l'héritage J'ai défini une classe dans l'Assemblée A et une sous-classe dans l'Assemblée B Après avoir ajouté l'attribut ci-dessous à l'Assemblée A, le problème est résolu:

[Assembly: SecurityRules(SecurityRuleSet.Level1, SkipVerificationInFullTrust = true)]
0
Homayoun Behzadian

J'ai trouvé que OfType avait des effets secondaires désagréables lors de l'utilisation de linq to sql. Par exemple, les parties de linq 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 par utiliser .Cast à la place, ce qui semble également résoudre le problème.

0
LaserJesus

Est-ce que cela échoue quand même si vous changez ceci:

select new SomeObject { ... } as ISomeTable;

pour ça:

select (ISomeTable) new SomeObject { ... };

?

Si c'est le cas (comme vous l'avez confirmé), cela tient peut-être au fait qu'une implémentation d'interface peut être une classe ou une structure Le problème persiste-t-il si vous convertissez une classe abstraite plutôt qu'une interface?

0
Av Pinzur

J'ai rencontré cette erreur en utilisant le "cadre d'accès aux données dynamiques" Bibliothèque passive . La source de l'erreur était la ligne 100 du fichier DynamicDatabase.cs.

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 ai lancé le projet et ai soumis la modification à l'auteur original.

Merci, Jason Baker, d’avoir indiqué la solution dans votre question initiale.

Notons que la bibliothèque d’origine fonctionnait bien sur ma machine locale et sur un VPS Rackspace, mais lorsque j’ai transmis le même code à un environnement d’hébergement partagé (GoDaddy et les sites en nuage de Rackspace), j’ai commencé à obtenir le message suivant: " Erreur.

0
Tod Birdsall

Dans mon cas, j'avais mal déclaré la propriété Storage dans l'attribut Column d'une classe Linq2SQL 

    [Column(Storage = "_Alias", DbType = "NVarChar(50)")]
    public string UserAlias
0
user1760527