2015-07-11 26 views
5

Mam dwie proste klasy.W jaki sposób Reflection.Emit może przypisać niezgodne typy?

public class A { } 
public class B { } 

Buduję i tworzę instancję klasy C jak poniżej.

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); 

Problemem jest to, mogę z powodzeniem instancję klasy C. Kiedy sprawdziłem typ i wartość C.A, było to dla mnie bardzo zaskakujące.

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 

Krótko, mam następujące klasy, które działają!

public class A { } 
public class B { } 

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

Moje pytania są następujące:

  1. Jak to możliwe?
  2. Na jakim poziomie CLR sprawdza typy?
+0

Właściwie wszystko działa tak, jak powinno. Typ pola, typ deklaracji i typ wartości pola są całkowicie różne od pokazanego testu. – leppie

+0

Następnie, w jaki sposób wykonuje konstruktora bez żadnych wyjątków? –

+0

Nie rozumiem, dlaczego spodziewasz się wyjątku. Czy otrzymujesz wyjątek w normalnym kodzie? A jaki wyjątek? – leppie

Odpowiedz

3

Jeśli twój kod działa pod pełnym zaufaniem, to CLR nie zadaje sobie trudu sprawdzenia, czy IL jest "weryfikowalny". Oznacza to, że kod może wykonywać różnego rodzaju zwariowane rzeczy, a to oznacza, że ​​twój emitowany kod jest bezpieczny.

Jeśli jednak twój kod działa pod częściowym zaufaniem, wtedy Activator.CreateInstance(type) rzuci System.Security.VerificationException ("Operacja może zdestabilizować środowisko wykonawcze").