2015-04-17 62 views
2

我需要通過僅反射才能使用位於新域內指定文件中的.dll庫。一切都很好,我可以獲取信息,方法,類型,但是當我真的想要Invoke方法之一時,異常會引發System.Reflection.TargetException(對象與目標對象不匹配)。毛刺是,當我設置「路徑」只有名稱爲「Filter.dll」的名稱,並在Debug目錄中有庫時,應用程序工作。當我移動庫並將其路徑更改爲@「D:/Dropbox/SchoolProject/MyPlugins/Filter.dll」時,會引發異常。如何通過ReflectionOnly正確獲取Type的方法用法

我的代碼:

AppDomain domain = AppDomain.CreateDomain("MyNewDomain"); //new domain for assembly 
//parameters are @"D:/Dropbox/SchoolProject/MyPlugins/Filter.dll", "Plugins.Filter" 
ObjectHandle objh = domain.CreateInstanceFrom(_selectedLibraryDirectives.Item1 + _selectedLibraryDirectives.Item2 + ".dll", _selectedLibraryDirectives.Item3);    
object obj = objh.Unwrap(); 

if (RemotingServices.IsTransparentProxy(obj)) 
{ 
    Type domainType = null; 
    foreach (var ass in AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies()) 
    { 
     //domainType's name and fullname is "Filter", "Plugins.Filter" 
     //so I would think this is type I want, but exception about wrong 
     //type is raised when using domainType for method.Invoke 
     domainType = ass.DefinedTypes.First().AsType(); 
    } 

    //type's name and fullname is "Filter", "Plugins.Filter", 
    //when Filter.dll is in Debug dir, even if name of the file in 
    //domain.CreateInstanceFrom is set to path to MyPlugins, invoking method works 
    //and "MarshalByRefObject", "System.MarshalByRefObject" in case library 
    // isn't in Debug directory, invoking method crashes on wrong type 
    Type type = obj.GetType(); 
    //get method by method name previously added as ListBox Item 
    MethodInfo method = domainType.GetMethod(PluginMethodsListBox.SelectedItem.ToString()); 
    //exception is usually raised with invoking 
    Tuple<string, string> tuple = (Tuple<string, string>)method.Invoke(domainType, new object[] { "hello" }); 
    PluginsPluginNameValueLabel.Text = method.Name; 
    PluginsPluginDescValueLabel.Text = tuple.Item2; 
}   

這是我第一次處理庫,反射僅這樣。我很困惑,爲什麼我可以在一個文件夾中使用庫,但不在其他文件夾中,即使條件相同。當我可以從默認文件夾以外的庫中獲取MethodInfo時,爲什麼我無法正確獲取它的類型。

的代碼,其餘用於獲取有關圖書館方法的信息,並保存到UI元素,當庫是由用戶選擇:

  foreach (var library in _libraries) 
      { 
       if (PluginsListBox.SelectedItem + ".dll" == library.Name) 
       { 
        //getting library info 
        Assembly ass = Assembly.ReflectionOnlyLoadFrom(library.DirectoryName + @"\" + library.Name); 
        var types = ass.GetTypes(); 
        Type type = null; 
        foreach (var t in types) 
        { 
         if (t.Name + ".dll" == library.Name) 
         { 
          _selectedLibraryDirectives = new Tuple<string, string, string>(library.DirectoryName [email protected]"\", t.Name, t.FullName); 
          type = t; 
         } 
        } 
        //viewing list of methods in ListBox 
        if (type != null) 
        { 
         PluginMethodsListBox.Items.Clear(); 
         foreach (MethodInfo method in type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)) 
         { 
          if (method.ReturnType == typeof(Tuple<string,string>) && method.GetParameters().Length == 1 && method.GetParameters()[0].ParameterType.FullName == "System.String") 
          { 
           var a = method.GetParameters(); 
           PluginMethodsListBox.Items.Add(method.Name);  
          } 

         } 
        } 
       }      
      }  

感謝爲解決或瞭解這一情況的任何意見問候。

編輯(庫代碼):

[Serializable] 
public class Filter : MarshalByRefObject 
{ 
    public void noParamConsTest() { Console.WriteLine("noparamconsoletest");} 
    public void paramConstTest(string s) { Console.WriteLine(s); } 
    public Tuple<string,string> FilterCommas(string text) 
    { 
     //.. 
     return new Tuple<string, string>(returnString, string.Empty); 
    } 

解決方案:

我沒有爲propper,乾淨優雅的解決方案足夠多的時間,所以我改變做法了一下。我通過插件目錄設置文件觀察器,當發生更改時,我只是將庫複製到CurrentDomain工作目錄。從那裏裝載組件根本沒有問題。

但我的問題沒有得到答覆。爲什麼AppDomain,即使他們已經將基路徑,相對路徑等設置爲自定義路徑,在缺省工作目錄中查找庫,而不是指定庫或其中的庫。只從自定義目錄加載庫到新的域似乎是不可能的。

如果有人知道解釋,請讓我知道。謝謝

+0

很好的組裝var名稱(+1) – silver

回答

1

你應該調用的實例obj的方法,而不是類型domainType

Tuple<string, string> tuple = (Tuple<string, string>)method.Invoke(obj, new object[] { "hello" }); 

關於反思,只有:

不要在反射只讀模式加載程序集,如果你想要調用它的代碼。

Assembly.ReflectionOnlyLoad

加載組件進入只反射上下文,在那裏它可以是 檢驗,但不會執行。

使用常規的Assembly.Load方法之一。

+0

即使我嘗試這種方法,問題perzists。我需要爲加載的程序集創建新的域,所以我有這個代碼 'AppDomain domain = AppDomain.CreateDomain(「NewDomainName」,new Evidence(),new AppDomainSetup(){ApplicationName =「FriendlyName」,ApplicationBase = _selectedLibraryDirectives.Item1} ); domain.Load(「Filter」);' 但仍然,我將ApplicationBase設置到我的目錄,當我有默認目錄Filter.dll時,程序集加載,當我將Filter.dll移動到我的目錄時,FileNotFoundException被引發與過濾器全名 – Qerts

+0

的消息它看起來像我無法更改此新域的探測目錄,但它已基地設置爲我的目錄路徑 – Qerts

+0

@Qerts,嘗試使用LoadFrom提供組裝路徑 – Guillaume

相關問題