2011-05-22 43 views
8

我試圖使用CurrentDomain.AssemblyResolve事件加載標記爲嵌入式資源的DLL。我的問題,具體而言,來自於一個事實,我嘗試使用組件的子類,像這樣:當將程序集用作子類時,CurrentDomain.AssemblyResolve不會觸發

#define BROKEN 
using System; 
using System.Reflection; 
using TestCompanyInc; 

namespace TestConsole 
{ 
#if BROKEN 
    // This is how I NEED to use it 
    class Program : SubClass 
#else 
    // This is only here as a test to make sure I wired 
    // CurrentDomain.AssemblyResolve correctly 
    class Program 
#endif 
    { 
     static int Main(string[] args) 
     { 
      AppDomain.CurrentDomain.AssemblyResolve += (sender, eventArgs) => 
      { 
       string resourceName = Assembly.GetExecutingAssembly() 
         .GetName().Name 
         + "." + new AssemblyName(eventArgs.Name).Name + ".dll"; 
       Console.WriteLine("About to lookup {0}", resourceName); 

       using (var stream = Assembly.GetExecutingAssembly() 
         .GetManifestResourceStream(resourceName)) 
       { 
        byte[] assemblyData = new byte[stream.Length]; 
        stream.Read(assemblyData, 0, assemblyData.Length); 
        return Assembly.Load(assemblyData); 
       } 
      }; 

      Program p = new Program(args); 
      return p.Run(); 
     } 

     public Program(string[] args) 
     { 
     } 

     public int Run() 
     { 
#if BROKEN 
      // This is how I NEED to use it 
      Console.WriteLine(TestProperty); 
#else 
      // This is only here as a test to make sure I wired 
      // CurrentDomain.AssemblyResolve correctly 
      SubClass sc = new SubClass(); 
      Console.WriteLine(sc.TestProperty); 
#endif 
      Console.ReadKey(); 
      return 0; 
     } 
    } 
} 

測試類​​被定義爲:

namespace TestCompanyInc 
{ 
    public class SubClass 
    { 
     public SubClass() 
     { 
      TestProperty = "Init'd"; 
     } 
     public string TestProperty { get; set; } 
    } 
} 

如果第一行#define BROKEN未留下注釋,則CurrentDomain.AssemblyResolve事件將永遠不會觸發並引發System.IO.FileNotFoundException,並且我被告知​​找不到。如果第一行被刪除或註釋掉,那麼它會觸發事件(但我不能以這種方式使用它)。

我也曾嘗試移動Main到其自己的類,而不是具有相同類來創建自己的實例,但我得到完全相同的例外。

那麼,如何正確連接此事件,以便在這些條件下加載此程序集?


在VS 2010 .NET 4中編譯,如果這對任何人都有影響。此外,任何人試圖重新創建。子類在它自己的項目中。將SubClass添加爲TestConsole的引用並將其標記爲Copy Local = False。我已經在某處讀過,這不能是一個Project Reference,而是直接引用這個DLL。然後,將DLL 文件添加到TestConsole項目並將其標記爲嵌入式資源,而不是內容的默認值。

回答

19

想想加載順序...爲了JIT和調用Main,它必須瞭解Program。如果不加載需要特殊處理的基類,它就無法理解程序。該事件不會觸發,因爲它尚未註冊(因爲Main尚未啓動)。

這是行不通的。你能做到這一點的唯一方法就是擁有一個不依賴於其他任何東西的入口點。請注意,JIT在方法啓動之前完成,所以Main也不能涉及任何未知的東西。例如,你可以這樣做:

class Loader { 
    static void Main() 
    { 
     // not shown: register assemy-load here 
     MainCore(); 
    } 
    [MethodImpl(MethodImplOptions.NoInlining)] 
    static void MainCore() 
    { // your class as shown is Program 
     Program.Init(); 
    } 
} 

報告中,我們需要2種以上方法,因爲它不能JIT主,除非能完全解決方案。通過以上所述,事件應該在調用MainCore()之前觸發(即在MainCore的JIT期間)。

+0

哇,我幾乎** **那裏。我只是沒有想到將'Program'的運行轉移到另一種方法。現在,你能告訴我'[MethodImpl(MethodImplOptions.NoInlining)]'爲我做了什麼嗎?我評論它只是爲了看看會發生什麼,它仍然有效。 **感謝** – Jim 2011-05-22 16:26:37

+1

@Jim只是試圖確保它在Main的JIT期間不會嘗試合併Main和MainCore。預測相當時它會決定內聯一個方法是棘手的。 – 2011-05-22 16:30:06

+0

啊,好的。我想這可能是其中的一部分,如果它是一個未優化的調試版本與優化的版本構建。 – Jim 2011-05-22 16:55:21

相關問題