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

时间:2015-04-17 09:20:45

标签: c# .net

我需要通过反射仅使用位于新域内指定文件中的.dll库。一切都很好,我可以获得信息,方法,类型,但是当我真正想要Invoke方法之一时,会引发异常System.Reflection.TargetException(对象与目标对象不匹配)。当我设置为"路径"只有库的名称" Filter.dll"并在调试目录中有库,应用程序工作。当我移动库并将其路径更改为@" D:/Dropbox/SchoolProject/MyPlugins/Filter.dll"时,会引发异常。

我的代码:

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 +@"\", 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);
    }

解决方案:

我没有时间选择适当,干净和优雅的解决方案,所以我改变了一点方法。我将文件观察者设置为插件目录,当发生更改时,我只是将库复制到CurrentDomain工作目录。从那里装载组件完全没有问题。

但我的问题没有答案。为什么AppDomains,即使他们已经设置了自定义路径的基本路径,相对路径等,也会在默认工作目录中查找库而不是指定库或两者中的库。仅将自定义目录中的库加载到新域似乎对我来说是不可能的。

如果有人知道解释,请告诉我。谢谢

1 个答案:

答案 0 :(得分:1)

您应该在实例obj上调用该方法,而不是在domainType类型上调用

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

仅关于反思:

如果要调用其代码,请不要在仅反射模式下加载程序集。

Assembly.ReflectionOnlyLoad

  

将程序集加载到仅反射上下文中   检查但未执行。

使用常规Assembly.Load方法之一。