Accesso dell'utente su modulo può causare un'eccezione di runtime perché è un campo di una classe maresciallo-by-reference
-
10-10-2019 - |
Domanda
Accesso un membro su modulo può causare un'eccezione di runtime perché è un campo di una classe maresciallo per riferimento
So cosa questo avvertimento è e so come risolverlo.
La mia domanda è perché potrebbe questo causa un errore di runtime?
Soluzione
Probabilmente si sta parlando di avviso CS1690, il codice Repro:
public class Remotable : MarshalByRefObject {
public int field;
}
public class Test {
public static void Run() {
var obj = new Remotable();
// Warning CS1690:
Console.WriteLine(obj.field.ToString());
}
}
In uno scenario di servizi remoti, il metodo Test.Run lavorerà con un proxy dell'oggetto Remotable. Costruire un proxy per una proprietà, metodo o evento non è un gran problema, solo una questione di creare un MethodTable che contiene i sostituti. I campi sono un problema, tuttavia, non c'è niente da 'gancio'. Per un MBro, il compilatore JIT non genera il codice per accedere al campo direttamente, si inietta una chiamata a un metodo di supporto integrato nel CLR, JIT_GetField32 () in questo caso.
che controlla helper se l'oggetto è un proxy e utilizza l'impianto idraulico remoting per ottenere il valore remota se questo è il caso. O semplicemente accede al campo direttamente, se non lo è. Effettuare la chiamata ToString () tuttavia richiede il valore da scatola. Questo è un problema, il pugilato isola il valore dal proxy. Non v'è alcun modo per garantire che il valore boxed è sempre una copia fedele del valore telecomandato. Chiamando JIT_GetField32 () di nuovo quando il metodo ToString () utilizza il valore per formattare la stringa non è possibile.
La soluzione per CS1690 è semplice, al di là avvolgendo il campo con una proprietà, basta copiare il valore del campo in una variabile locale. Ora è chiaro che il codice sta lavorando con una copia e non c'è mai una sorpresa in modo che il compilatore non dovrà emettere un avvertimento.
public static void Run() {
var obj = new Remotable();
var value = obj.field;
Console.WriteLine(value.ToString()); // No warning
}
Altri suggerimenti
In aggiunta al suggerimento da @ Hans-passant, penso che un altro modo utile per risolvere questo avviso è da trasformare il campo in una proprietà.
public class Remotable : MarshalByRefObject {
public int field;
}
potrebbe diventare
public class Remotable : MarshalByRefObject {
public int field { get; set }
}
e si ottiene più alcun avvertimenti! (Hans Passant ha già una spiegazione eccellente per questo, vedi suo posto )
Ovviamente, non si può sempre modificare l'oggetto che si sta lavorando. (Esempio: WinForms dove i campi sono generati per voi) così si potrebbe avere per il fallback per utilizzare una variabile temporanea
Se l'altro lato dell'oggetto marshalling è morto, si getterà un errore di runtime che indica che l'oggetto di riferimento non esiste più.
In alternativa, è possibile scrivere:
var obj = new Remotable();
Console.WriteLine(((int) obj.field).ToString()); // No warning
Qui si prende la propria responsabilità per quel cast (unboxing).