L’operazione potrebbe destabilizzare il runtime?

Sto avendo un po ‘di problemi a capire quale sia il problema. Ho un po ‘di codice che estrae i record da un database usando LINQ e li inserisce in un object che viene inserito in un’interfaccia. Sembra un po ‘come questo:

public IEnumerable query() { return from a in dc.SomeTable select new SomeObject { //Assign various members here } as ISomeObject; } 

Quando provo questo, metto l’IEnumerable restituito in una variabile chiamata risultati ed eseguo questa linea:

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

Quando viene eseguito, ottengo un System.Security.VerificationException: “L’operazione potrebbe destabilizzare il runtime.”

Ho trovato la soluzione qui , che è questo:

 var results = from a in dc.SomeTable select new SomeObject { //Assign various members here } as ISomeTable; return results.OfType(); 

Funziona, ma ho difficoltà a capire cosa sta succedendo qui. Perché ho ottenuto l’eccezione in primo luogo e in che modo le righe di codice sopra lo hanno risolto? La documentazione MSDN sembra suggerire che si tratta di un problema di sicurezza del tipo, ma non vedo dove il codice precedente era di tipo non sicuro.

AGGIORNARE Altre informazioni che ho trovato. Il primo esempio funziona se si effettua il tipo restituito IQueryable. Questo getta un po ‘più di luce su quello che stava andando storto, ma sono ancora confuso sul perché . Perché il compilatore non mi ha obbligato a convertire l’object IEnumerable in un IQueryable?

Credo che sia un problema di covarianza o contravarianza come notato da questo post sul forum .

Vedi Covariance and Contravariance in C #, Seconda parte: Array Covariance e il resto della serie Covariance and Contravariance sul blog di Eric Lippert.

Sebbene abbia a che fare con gli array nell’articolo che ho collegato, credo che un problema simile si presenti qui. Con il tuo primo esempio, stai restituendo un object IEnumerable che potrebbe contenere oggetti che implementano un’interfaccia più grande di ISomeTable (ad esempio, potresti inserire una tartaruga in un animale IEnumerable quando quell’Enumerable può contenere solo giraffe). Penso che il motivo per cui funziona quando ritorni IQueryable è perché è più grande / più ampio di qualsiasi cosa tu possa restituire, quindi ti garantiamo che ciò che ritorni sarai in grado di gestire (?).

Nel secondo esempio, OfType garantisce che ciò che viene restituito è un object che memorizza tutte le informazioni necessarie a restituire solo quegli elementi che possono essere trasmessi a Giraffe.

Sono abbastanza sicuro che abbia qualcosa a che fare con i problemi di sicurezza del tipo descritti sopra, ma come Eric Lippert dice che le funzioni di ordine superiore mi feriscono il cervello e ho difficoltà a esprimere precisamente perché questo è un problema co-controverso.

Ho trovato questa voce mentre cercavo la mia soluzione per “l’operazione potrebbe destabilizzare il runtime”. Mentre il consiglio di covarianza / contro-varianza di cui sopra sembra molto interessante, alla fine ho scoperto che ottengo lo stesso messaggio di errore eseguendo i miei test unitari con la copertura del codice triggersta e l’attributo di assembly AllowPartiallyTrustedCallers impostato.

La rimozione dell’attributo AllowPartiallyTrustedCallers ha causato il corretto funzionamento dei miei test. Potrei anche distriggersre la copertura del codice per farli funzionare, ma quella non era una soluzione accettabile.

Speriamo che questo aiuti qualcun altro che lo fa a questa pagina cercando di trovare una soluzione a questo problema.

Solo un’ipotesi, ma l’operatore as potrebbe restituire un valore null, quindi potrebbe avere a che fare con l’effettiva implementazione del new SomeObject { ... } , dal momento che è zucchero sintattico. Il return results.OfType(); filtri basati sul tipo, quindi la dichiarazione di ritorno del metodo restituirà solo quel tipo (garantendo la sicurezza del tipo). Ho riscontrato un problema simile con la restituzione di tipi generici.

PS Adoro “L’operazione potrebbe destabilizzare il runtime”. eccezione. È quasi come l’eccezione “Potresti far saltare in aria internet”.

Mi sono imbattuto in questo errore con codice simile;

 IEnumerable records = (from t in db.Tables where t.Id.Equals(1) select t).ToList();

Questo codice apparentemente innocuo faceva parte di un metodo UserControl chiamato da una pagina. Nessun problema in un ambiente di sviluppo .NET4, tuttavia, quando il sito è stato PreCompiled e distribuito sul server su .NET 3.0 ho ricevuto questo errore.

Sospetto che ciò abbia a che fare con il fatto che il controllo è stato compilato in una DLL separata combinata con le modifiche alla sicurezza tra i framework come descritto in questo blog sulla sicurezza .NET.

La mia soluzione: esegui il sito live su .NET4

Ha ancora esito negativo se si modifica questo:

 select new SomeObject { ... } as ISomeTable; 

a questa:

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

?

Se è così (come ho visto che hai confermato), forse questo ha a che fare con il fatto che un’implementazione dell’interfaccia potrebbe essere una class o una struttura? Il problema si verifica ancora se si esegue il cast su una class astratta piuttosto che un’interfaccia?

Ho scoperto che OfType ha alcuni brutti effetti collaterali quando si usa linq su sql. Ad esempio, parti del linq che sono state precedentemente valutate dopo l’esecuzione della query sul db sono state invece tradotte in SQL. Questo non è riuscito in quanto tali sezioni non avevano equivalenti SQL. Alla fine ho usato .Cast, che sembra risolvere il problema.

Nel mio caso ho dichiarato erroneamente la proprietà Storage nell’attributo Column di una class Linq2SQL

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

Ho avuto lo stesso problema, ma con l’ereditarietà ho definito una class nell’assembly A e una sottoclass nell’assembly B dopo aver aggiunto l’attributo sotto all’assembly A, problema risolto:

 [assembly: SecurityRules(SecurityRuleSet.Level1, SkipVerificationInFullTrust = true)] 

Mi sono imbattuto in questo errore mentre utilizzavo la libreria passiva “Dynamic data access framework”. La fonte dell’errore era la riga 100 nel file DynamicDatabase.cs.

 databaseDetectors = (databaseDetectors ?? Enumerable.Empty()).DefaultIfEmpty(new DatabaseDetector()); 

Ho cambiato quella riga di codice in:

 databaseDetectors = (databaseDetectors ?? Enumerable.Empty()).DefaultIfEmpty(new DatabaseDetector()).OfType(); 

Farlo risolve il problema. Sono andato avanti e ho biforcato il progetto e ho presentato la modifica all’autore originale.

Grazie, Jason Baker, per aver indicato la soluzione nella tua domanda originale.

Nota a margine, la libreria originale funzionava bene sul mio computer locale e su un VPS Rackspace, ma quando ho trasmesso lo stesso codice a un ambiente di hosting condiviso (GoDaddy e Rackspace’s Cloud Sites), ho iniziato a ottenere che l’operazione potesse destabilizzare il runtime “errore.

Suppongo che Linq to Sql potrebbe non supportare il casting quando si traduce in istruzione sql.