Given these types (unknown at compile time)
public class Type0
{
public List<Type1> EnumerableProperty { get; set; }
}
public class Type1 { }
I'm trying to generate the following types using IL
public class GeneratedType0
{
private Type0 _content;
public GeneratedType0(Type0 arg)
{
_content = arg;
}
public List<Type1> EnumerableProperty => _content.EnumerableProperty.Select(x => new GeneratedType1(x));
}
public class GeneratedType1
{
private Type1 _content;
public GeneratedType1(Type1 arg)
{
_content = arg;
}
}
I have everything down, except for the use of a lambda inside the Select
method. The following code is my best attempt to add a IEnumerable property to a generated type.
Does anybody know what's wrong with my IL code supposed to add the property to the generated type?
public static readonly MethodAttributes _getAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
public static readonly MethodAttributes _getLambdaAttributes = MethodAttributes.Public | MethodAttributes.Static;
public static void AddEnumerableProperty(PropertyInfo property, Type initialPropertyElementType, Type propertyType, Type elementType, TypeBuilder builder, FieldBuilder fieldBuilder)
{
var propertyBuilder = builder.DefineProperty(property.Name, PropertyAttributes.None, propertyType, null); // EnumerableProperty on GeneratedType0
var getterBuilder = builder.DefineMethod($"get_{property.Name}", _getAttributes, propertyType, Type.EmptyTypes);
var propertyGetterIL = getterBuilder.GetILGenerator();
propertyGetterIL.Emit(OpCodes.Ldarg_0); //this
propertyGetterIL.Emit(OpCodes.Ldfld, fieldBuilder); //.content
propertyGetterIL.Emit(OpCodes.Callvirt, property.GetGetMethod() ?? throw new ArgumentException($"Property {property.Name} is not readable on type {property.DeclaringType}.")); //.property
var lambda = builder.DefineMethod("To" + elementType.Name, _getLambdaAttributes, CallingConventions.Standard, elementType, new[] { initialPropertyElementType });
var lambdaGenerator = lambda.GetILGenerator();
lambdaGenerator.Emit(OpCodes.Ldarg_0); //arg
lambdaGenerator.Emit(OpCodes.Newobj, elementType.GetConstructors()[0]);//new(...)
lambdaGenerator.Emit(OpCodes.Ret); //return
propertyGetterIL.Emit(OpCodes.Ldobj, lambda;// //ToElementType
var method = SelectMethod.MakeGenericMethod(initialPropertyElementType, elementType);
propertyGetterIL.Emit(OpCodes.Call, method);//Select<TInput, TResult>(
propertyGetterIL.Emit(OpCodes.Ret); //return
propertyBuilder.SetGetMethod(getterBuilder);
}
Aucun commentaire:
Enregistrer un commentaire