如何向在发出时类型未完成的委托发出调用?
我在发出对其类型在发出时未完成的委托的调用时遇到问题。我将详细说明:我已经声明了以下委托类型:
// Delegate type. The 'firstArgument' will be 'this', i.e., this is an open
// instance method: the implicit argument is here given explicitly, in
// 'firstArgument'. (See link below for explanation on open instance delegates).
public delegate Object DirectReadAccessor<T>(T firstArgument);
现在我正在尝试动态(即使用 TypeBuilder)创建以下类:
public MyClass {
// Array of delegates. T has been replaced with MyClass because the
// argument will be 'this', which is of type MyClass.
private static DirectReadAccessor<MyClass>[] directReadAccessors;
// Method that looks up a delegate in the array of delegates and calls it
// with 'this'.
public Object DirectRead(int i) {
directReadAccessors[i](this);
}
// Method that is called by the declaring type to pass an array with the
// MethodInfo of some methods. MyClass then creates delegates for these
// methods and stores them in the directReadAccessors array.
public static void InitializeClass(MethodInfo[] directReadAccessorsMInfo) {
int length = directReadAccessorsMInfo.Length;
Type[] typeArguments = new Type[] { typeof(MyClass) };
directReadAccessors = new DirectReadAccessor<MyClass>[length];
// For each method in directReadAccessorsMInfo...
for (int i = 0; i < length; i++) {
// Create a delegate and store it in directReadAccessors.
directReadAccessors[i] = (DirectReadAccessor<MyClass>)
Delegate.CreateDelegate(
DirectReadAccessor<MyClass>, // Type of the delegate.
null, // Specify null first argument so that it's
// *open* instance.
directReadAccessorsMInfo[i].MakeGenericMethod(typeArguments) // The method.
);
}
}
}
*on 开放实例委托。
这很棘手,因为当我尝试声明字段 directReadAccessors(类型为 DirectReadAccessor[])时,或者当我发出方法 InitalizeClass(再次使用 MyClass)时,MyClass 不存在,该方法还不存在(即我正在创造什么)。然而,我已经成功地完成了这一切,但现在我在使用 DirectRead 方法时遇到了麻烦,因为我不知道在将委托放入堆栈后如何调用该委托。显然我需要的是以下发出:
ilGenerator.Emit(OpCodes.Callvirt, invokeMInfo);
其中invokeMInfo是DirectReadAccessor上的Invoke方法,我应该像这样获得它:
MethodInfo invokeMInfo = typeof(DirectReadAccessor<MyClass>).GetMethod(
"Invoke", // Name of the method.
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, // Binding attributes.
null, // Binder.
new Type[] { typeof(MyClass) }, // Types of the arguments.
null // Modifiers for the arguments.
);
同样,问题是MyClass和DirectReadAccessor都不存在。我有 MyClass 的 TypeBuilder 和未完成的 DirectReadAccessor 类型,我是这样创建的:
directReadAccessorType = typeof(DirectReadAccessor<>).MakeGenericType(typeBuilder);
但是,如果我尝试在 directReadAccessorType 上调用 GetMethod("Invoke", ....) 如上所示,我会得到一个 NotSupportedException,因为我不能获取未完成类型的 Invoke 方法。我通过在最终确定类型后进行相同的调用来测试了这个假设:
typeBuilder.CreateType();
事实上,在这种情况下我没有得到异常。但是,当我发出 InitializeClass 的代码时,我需要能够在最终确定类型之前获取 Invoke 方法的 MethodInfo。
这是一个奇怪的情况:当我需要它时我会拥有委托,但我无法生成调用它的代码。有人可以提供任何帮助吗?
非常感谢,并对冗长的帖子表示歉意。
I'm having trouble emitting a call to a delegate whose type is unfinished at the time of the emit. I'll elaborate: I've declared the following delegate type:
// Delegate type. The 'firstArgument' will be 'this', i.e., this is an open
// instance method: the implicit argument is here given explicitly, in
// 'firstArgument'. (See link below for explanation on open instance delegates).
public delegate Object DirectReadAccessor<T>(T firstArgument);
And now I'm trying to dynamically (i.e., with a TypeBuilder) create the following class:
public MyClass {
// Array of delegates. T has been replaced with MyClass because the
// argument will be 'this', which is of type MyClass.
private static DirectReadAccessor<MyClass>[] directReadAccessors;
// Method that looks up a delegate in the array of delegates and calls it
// with 'this'.
public Object DirectRead(int i) {
directReadAccessors[i](this);
}
// Method that is called by the declaring type to pass an array with the
// MethodInfo of some methods. MyClass then creates delegates for these
// methods and stores them in the directReadAccessors array.
public static void InitializeClass(MethodInfo[] directReadAccessorsMInfo) {
int length = directReadAccessorsMInfo.Length;
Type[] typeArguments = new Type[] { typeof(MyClass) };
directReadAccessors = new DirectReadAccessor<MyClass>[length];
// For each method in directReadAccessorsMInfo...
for (int i = 0; i < length; i++) {
// Create a delegate and store it in directReadAccessors.
directReadAccessors[i] = (DirectReadAccessor<MyClass>)
Delegate.CreateDelegate(
DirectReadAccessor<MyClass>, // Type of the delegate.
null, // Specify null first argument so that it's
// *open* instance.
directReadAccessorsMInfo[i].MakeGenericMethod(typeArguments) // The method.
);
}
}
}
This has been tricky because MyClass doesn't exist when I'm trying to declare the field directReadAccessors, which is of type DirectReadAccessor[], or when I emit the method InitalizeClass, which again uses MyClass, that doesn't exist yet (that's what I'm creating). However, I've managed to do all this, but now I'm having trouble with method DirectRead, since I don't know how to call the delegate once I have it on the stack. Apparently what I need is the following emit:
ilGenerator.Emit(OpCodes.Callvirt, invokeMInfo);
where invokeMInfo is the method Invoke on DirectReadAccessor, and which I should obtain like so:
MethodInfo invokeMInfo = typeof(DirectReadAccessor<MyClass>).GetMethod(
"Invoke", // Name of the method.
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, // Binding attributes.
null, // Binder.
new Type[] { typeof(MyClass) }, // Types of the arguments.
null // Modifiers for the arguments.
);
Again, the problem is that neither MyClass nor DirectReadAccessor exist yet. I have the TypeBuilder for MyClass and the unfinished DirectReadAccessor type, which I've created like this:
directReadAccessorType = typeof(DirectReadAccessor<>).MakeGenericType(typeBuilder);
But if I try to call GetMethod("Invoke", ....) on directReadAccessorType as shown above I get a NotSupportedException, because I cannot obtain the method Invoke for an unfinished type. I've tested this assumption by making the same call after finalizing the type with:
typeBuilder.CreateType();
And indeed I do not get the exception in that case. However, I need to be able to get the Invoke method's MethodInfo before finalizing the type, while I'm emitting the code for InitializeClass.
It's a strange situation: I'll have the delegate when I need it, but I cannot produce the code to invoke it. Can anyone offer any help?
Thanks so much, and sorry for the lengthy post.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是一个棘手的问题。我认为您应该能够使用
TypeBuilder.GetMethod
来获取您需要的MethodInfo
,使用以下调用That's a tricky problem. I think that you should be able to use
TypeBuilder.GetMethod
to get theMethodInfo
you need, using a call along the lines of您是否尝试过编译通用代码并使用 ILDASM 查看它?它应该向您显示正确的 IL,并希望生成正确的发射。
Have you tried to compile the generic code and look at it using ILDASM ? It should show you the correct IL and hopefully the right emit to generate.
最小化生成的类中的代码量是否有意义?
我的意思是生成的类可以实现一个可以访问其数据的接口。通过它,您可以实现可以用 C# 而不是 IL 编码的附加功能。
Would it make sense to minimize the amount of code in the generated class ?
By that, I mean that the generated class could implement an interface that gives access to its data. Through it, you could implement additional features that could be coded in C# instead of IL.