samedi 11 juillet 2015

How Reflection.Emit can assign invalid types?

I have two simple classes.

public class A { }
public class B { }

I build and instantiate class C like below.

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

The problem is I can successfully instantiate class C. When I check the type and value of C.A it was very surprising for 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

Briefly, I have following classes which are working!

public class A { }
public class B { }

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

My questions are:

  1. How can this be possible?
  2. At which level does CLR checks the types?




Aucun commentaire:

Enregistrer un commentaire