如何通过ReflectionOnly正确获取Type的方法用法

问题描述:

我需要通过仅反射才能使用位于新域内指定文件中的.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

你应该调用的实例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