2010-03-03 33 views
3

我在发出呼叫给发出时其类型未完成的代理时遇到问题。我会详细说明:我已经声明了以下委托类型:如何在发出时向未完成类型的代理发出呼叫?

// 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. 
        ); 
     } 
    } 

} 

*上open instance delegates

这一直很棘手,因为当我试图声明字段directReadAccessors,它是DirectReadAccessor []类型,或者当我发出方法InitalizeClass,它再次使用MyClass时,MyClass不存在存在(这就是我创建的)。不过,我设法做到了这一切,但现在我在DirectRead方法中遇到了问题,因为我不知道如何在堆栈中调用委托时调用该委托。显然,我需要的是下面的Emit:

ilGenerator.Emit(OpCodes.Callvirt, invokeMInfo); 

其中invokeMInfo是DirectReadAccessor的方法调用,而我应该得到像这样:

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的和未完成的DirectReadAccessor类型TypeBuilder,我已经是这样创建的:

directReadAccessorType = typeof(DirectReadAccessor<>).MakeGenericType(typeBuilder); 

但是,如果我尝试调用GetMethod(“调用”,....)上directReadAccessorType如上图所示,我得到一个NotSupportedException,因为我无法获取未完成类型的方法Invoke。我已经最后定稿类型后进行相同的呼叫测试这个假设:

typeBuilder.CreateType(); 

事实上我不明白在这种情况下例外。不过,我需要能够在最终确定类型之前获取Invoke方法的MethodInfo,同时发出InitializeClass的代码。

这是一个奇怪的情况:当我需要它时,我将拥有委托,但是我无法生成代码来调用它。任何人都可以提供帮助吗?

非常感谢,对于冗长的帖子感到抱歉。

+0

没有进攻的线路的呼叫,但它只是我,还是开发者编写的代码是太复杂了? ? – 2010-03-03 08:31:49

+0

没有采取。这是一个为期5个月的项目,尝试将C#移植到一个非常复杂的预先存在的系统中。 事实上,我在这里试图做的并不是那么复杂,我只是有一个委托阵列,并希望能够调用它们,就这些。唯一的问题是我正在使用一个动态创建的类型,但是如果你不允许使用这种类型,那么首先提供这个功能有什么意义? – Alix 2010-03-03 10:07:53

回答

4

这是一个棘手的问题。我认为你应该能够使用TypeBuilder.GetMethod得到MethodInfo需要,使用沿着

TypeBuilder.GetMethod(directReadAccessorType, 
    typeof(DirectReadAccessor<>).GetMethod("Invoke")); 
+0

哦,我的天啊,就是这样。有用!非常感谢,非常感谢,我一直在为此奋斗! (它变得非常令人沮丧;我无法找到所需的图书馆电话,就像这样)。再次感谢,你真的让我的一天! :) – Alix 2010-03-04 08:04:03

+0

@Alix - 我很高兴能够提供帮助。不幸的是,'TypeBuilder'上的静态'GetMethod','GetField'和'GetConstructor'方法不易被发现,因此在使用Reflection.Emit和泛型进行复杂的工作时容易陷入困境。 – kvb 2010-03-04 15:52:18

+0

告诉我关于它:)。我已经编程了多年(不是用C#编写的),而且我通常不需要在论坛上提出太多问题,但是自从几个星期前我开始使用C#之后,我不得不问很多问题。当然,我想要做的一些东西有点不寻常:) – Alix 2010-03-04 18:41:23

0

您是否尝试编译通用代码并使用ILDASM查看它?它应该告诉你正确的IL,并希望右侧发射产生。

+0

嗨。是的,我在上面说“显然我需要的就是下面的发射”,发射就像你所建议的那样获得。问题是我认为我可以在运行时(我这样做)将委托加载到堆栈上,并按原样调用它,而不必在发出代码时提供特定于委托类型的Invoke方法(因为类型doesn现在还没有)。 – Alix 2010-03-03 10:04:39

0

将生成的类中的代码量最小化是否有意义?

由此,我的意思是生成的类可以实现访问其数据的接口。通过它,您可以实现可以使用C#而非IL编码的附加功能。

+0

嗨。问题是这是一个系统,它接受用户编写的类(在这种情况下是应用程序员),并使用一些功能扩展它们,并且最重要的是确保安全地访问字段(通过其代表我拥有的访问器在数组directReadAccessors中)。所有这一切都必须自动完成,我不想强​​迫用户编写接口等。我必须通过动态发布类来完成所有这些工作。如果你对如何做得更好有任何想法,请告诉我。谢谢! – Alix 2010-03-03 12:47:58

+0

我不知道我是否理解你的需求(应用程序员似乎应该能够用一种方法实现一个接口),但解决该问题的另一种方法可能是生成C#并通过调用csc编译它,然后加载结果DLL。 或者提供构建步骤或脚本来完成它,以便应用程序员引用此生成的DLL。 – Timores 2010-03-03 13:13:00

+0

“这是一个系统,它需要用户编写的类” - * shivers * – 2010-03-04 04:57:02