So I have a class:
public class MyClass : IMyClass
{
public string foo {get;}
public MyClass bar {get;}
}
And an interface:
public interface IMyClass
{
string foo {get;}
}
And a system to create an emitted type:
private static Type MakeDynamicType<T>() where T : class
{
var myType = GetTypeBuilder();
myType.AddInterfaceImplementation(typeof(T));
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties)
AddProperty(myType, property, typeof(T));
AddCtor(myType, typeof(T));
return myType.CreateType();
}
private static void AddCtor(TypeBuilder myType, Type inputParamType)
{
var myCtor = myType.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null);
var ilGenerator = myCtor.GetILGenerator();
ilGenerator.Emit(OpCodes.Ret);
}
private const MethodAttributes GET_SET_ATTR = MethodAttributes.Public | MethodAttributes.SpecialName |
MethodAttributes.HideBySig | MethodAttributes.Virtual;
private static void AddProperty(TypeBuilder myType, PropertyInfo property, Type interfaceType)
{
var myField = myType.DefineField($"m_{property.Name}", property.PropertyType, FieldAttributes.Private);
var myProperty = myType.DefineProperty(property.Name, PropertyAttributes.HasDefault, property.PropertyType,
parameterTypes: null);
var interfaceGetMethod = interfaceType.GetMethod($"get_{property.Name}");
if (interfaceGetMethod != null)
AddGetter(myType, property, myField, myProperty, interfaceGetMethod);
var interfaceSetMethod = interfaceType.GetMethod($"set_{property.Name}");
if (interfaceSetMethod != null)
AddSetter(myType, property, myField, myProperty, interfaceSetMethod);
}
private static void AddGetter(TypeBuilder myType, PropertyInfo property, FieldInfo myField,
PropertyBuilder myProperty, MethodInfo interfaceGetMethod)
{
var myGet = myType.DefineMethod($"get_{property.Name}", GET_SET_ATTR, property.PropertyType,
Type.EmptyTypes);
var getIl = myGet.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, myField);
getIl.Emit(OpCodes.Ret);
myProperty.SetGetMethod(myGet);
myType.DefineMethodOverride(myGet, interfaceGetMethod);
}
private static void AddSetter(TypeBuilder myType, PropertyInfo property, FieldInfo myField,
PropertyBuilder myProperty, MethodInfo interfaceSetMethod)
{
var mySet = myType.DefineMethod($"set_{property.Name}", GET_SET_ATTR, returnType: null,
new[] { property.PropertyType });
var setIl = mySet.GetILGenerator();
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldarg_1);
setIl.Emit(OpCodes.Stfld, myField);
setIl.Emit(OpCodes.Ret);
myProperty.SetSetMethod(mySet);
myType.DefineMethodOverride(mySet, interfaceSetMethod);
}
private static TypeBuilder GetTypeBuilder()
{
var myDomain = Thread.GetDomain();
var myAsmName = new AssemblyName("MyDynamicAssembly");
var myAsmBuilder = myDomain.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.RunAndSave);
var myModBuilder = myAsmBuilder.DefineDynamicModule(myAsmName.Name, myAsmName.Name + ".dll");
return myModBuilder.DefineType("MyDynamicType", TypeAttributes.Public);
}
So now how do I create an instance of my reflected type from an IMyClass type reference to a MyClass object?
public static IEnumerable<T> ToInterfacedObjects<T>(this IEnumerable<T> data) where T : class
{
var myType = MakeDynamicType<T>();
var list = new List<T>();
foreach (var datum in data)
{
list.Add((T)myType.GetValue(datum));//What do I write for GetValue??
}
return list;
}
My goal is to start with an IMyClass
which has an underlying type of MyClass
, which has both foo and bar, and end with an IMyClass
which has an underlying type of an emitted type, which has foo
but not bar
.
If you've got an implementation for MakeDynamicType<T>
, and assuming your interface has only simple {get; set;}
properties, wouldn't this be as simple as:
public static IList<T> ToInterfacedObjects<T>(this IEnumerable<T> data) where T : class
{
var myType = MakeDynamicType<T>();
var list = new List<T>();
foreach (var datum in data)
{
var obj = (T)Activator.CreateInstance(myType);
foreach (var pi in typeof(T).GetProperties())
{
var val = pi.GetValue(datum);
pi.SetValue(obj, val);
}
list.Add(obj);
}
return list;
}