2010-03-03 45 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

相關問題