2015-07-11 13 views
5

Ho due classi semplici.In che modo Reflection.Emit può assegnare tipi incompatibili?

Io costruisco e istanzio classe C come di seguito.

var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Some.Namespace"), AssemblyBuilderAccess.Run); 
var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyBuilder.GetName().Name); 

// public class C 
var typeBuilder = moduleBuilder.DefineType("C", TypeAttributes.Public | TypeAttributes.Class, typeof(object)); 

// public A A; 
var aField = typeBuilder.DefineField("A", typeof(A), FieldAttributes.Public); 

// public C() { this.A = new B(); } !!!! 
var ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, Type.EmptyTypes); 
var ctorIL = ctorBuilder.GetILGenerator(); 
ctorIL.Emit(OpCodes.Ldarg_0); 
ctorIL.Emit(OpCodes.Newobj, typeof(B).GetConstructor(Type.EmptyTypes)); 
ctorIL.Emit(OpCodes.Stfld, aField); 
ctorIL.Emit(OpCodes.Ret); 

// return new C(); 
var type = typeBuilder.CreateType(); 
return Activator.CreateInstance(type); 

Il problema è che posso istanziare successo di classe C. Quando controllo il tipo e il valore di C.A è stato molto sorprendente per me.

var c = CreateC(); 

var field = c.GetType().GetField("A"); 
var fieldValue = c.GetType().GetField("A").GetValue(c); 

Console.WriteLine(typeof(A) == field.FieldType);  // True 
Console.WriteLine(typeof(A) == fieldValue.GetType()); // False 
Console.WriteLine(typeof(B) == field.FieldType);  // False 
Console.WriteLine(typeof(B) == fieldValue.GetType()); // True 

In breve, ho le seguenti classi che funzionano!

public class A { } 
public class B { } 

public class C 
{ 
    public A A; 
    public C() 
    { 
     this.A = new B(); 
    } 
} 

Le mie domande sono:

  1. come può essere possibile?
  2. A quale livello CLR controlla i tipi?
+0

In realtà tutto funziona come dovrebbe. Un tipo di campo, un tipo di dichiarazione e un tipo di valore di campo sono completamente diversi rispetto al test mostrato. – leppie

+0

Quindi, come viene eseguito il costruttore senza alcuna eccezione? –

+0

Non capisco perché ti aspetti un'eccezione. Hai un'eccezione nel codice normale? E quale eccezione? – leppie

risposta

3

Se il codice viene eseguito con piena attendibilità, il CLR non si preoccupa di controllare che l'IL sia "verificabile". Ciò significa che il codice può fare ogni sorta di cose pazze, ed è la tua responsabilità per assicurarti che il codice che emetti sia sicuro.

Tuttavia, se il codice viene eseguito con un trust parziale, Activator.CreateInstance(type) genererà System.Security.VerificationException ("L'operazione potrebbe destabilizzare il runtime").