使用Reflection Emit创建一个构造函数调用,该调用将Func<>作为参数传递。

5

我希望有人能够指导我解决以下问题。

我正在处理一个使用Reflection.Emit生成类型的项目,一切都很顺利,直到出现了一个需求:我需要将一个Func<>传递给一个新对象的构造函数,如下所示。

public class SearchTerm : IEntity
{
   private readonly NavigationProperty<Item> _item;

   public SearchTerm()
   {
       _item = new NavigationProperty<Item>(() => ItemIds);
   }
   public string[] ItemIds { get; set; }
}

使用Linqpad,我可以看到IL输出如下:
SearchTerm.<.ctor>b__0:
IL_0000:  ldarg.0     
IL_0001:  call        UserQuery+SearchTerm.get_ItemIds
IL_0006:  stloc.0     // CS$1$0000
IL_0007:  br.s        IL_0009
IL_0009:  ldloc.0     // CS$1$0000
IL_000A:  ret         

SearchTerm..ctor:
IL_0000:  ldnull      
IL_0001:  stloc.0     
IL_0002:  ldarg.0     
IL_0003:  call        System.Object..ctor
IL_0008:  nop         
IL_0009:  nop         
IL_000A:  ldarg.0     
IL_000B:  ldloc.0     
IL_000C:  brtrue.s    IL_001D
IL_000E:  ldarg.0     
IL_000F:  ldftn       UserQuery+SearchTerm.<.ctor>b__0
IL_0015:  newobj      System.Func<System.Collections.Generic.IEnumerable<System.String>>..ctor
IL_001A:  stloc.0     
IL_001B:  br.s        IL_001D
IL_001D:  ldloc.0     
IL_001E:  newobj      UserQuery<UserQuery+Item>+NavigationProperty`1..ctor
IL_0023:  stfld       UserQuery+SearchTerm._item
IL_0028:  nop         
IL_0029:  ret  

我遇到的问题是我不确定如何在IL中定义委托。

我尝试了以下方法:

var method = typeBuilder.DefineMethod("func", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(IEnumerable<string>), Type.EmptyTypes);

var methodIl = method.GetILGenerator();
methodIl.Emit(OpCodes.Ldarg_0);
methodIl.Emit(OpCodes.Call, dictionary["get_ItemIds"]);
methodIl.Emit(OpCodes.Ret);

尝试创建委托时,以下内容会抛出“不支持的异常”,并显示错误消息“派生类必须提供实现。”

var funcType = typeof(Func<,>).MakeGenericType(typeBuilder, typeof(IEnumerable<string>));
method.CreateDelegate(funcType);

我也尝试过使用Delegate.CreateDelegate和DynamicMethod,但这两种方法都需要在使用它们之前先创建类型。

如果您对我可能做错了什么有任何建议,将不胜感激。

1个回答

2

如果你想调用你的代码,你需要使用TypeMethodInfo,而不是TypeBuilderMethodBuilder

因此,你需要先CreateType(),然后使用该Type和它的方法:

var generatedType = typeBuilder.CreateType();

var funcType = typeof(Func<,>).MakeGenericType(
    generatedType, typeof(IEnumerable<string>));
var d = generatedType.GetMethod("func").CreateDelegate(funcType);

所以在你有实际类型之前,你不能创建委托?只是为了确认一下,我目前正在使用TypeBuilder生成的Class SearchTerm不会包含_item = new NavigationProperty<Item>(() => ItemIds),因为我需要调用createType来在委托中使用类的属性。顺便说一句,谢谢你的回复。 - SCB
@SCB 我不明白为什么你需要创建委托的实例来生成那段代码。你需要生成用于创建委托的代码,而不仅仅是创建委托本身。 - svick
好的,但是我的SearchTerm构造函数会创建一个新的NavigationProperty对象,我需要将一些内容传递给该对象的构造函数调用。 - SCB
1
@SCB 是的,但你需要生成能够实现这一点的代码,而不是真正调用 CreateDelegate()。你应该做的是:1. 创建“匿名”方法(实际上是普通方法,在 IL 中没有匿名方法)。2. 生成代码,使用 ldftn yourMethodnewobj Func<GeneratedType, IEnumerable<string>> 创建委托。 - svick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接