C# 如何通过ReflectionOnly正确获取方法使用的类型

C# 如何通过ReflectionOnly正确获取方法使用的类型,c#,.net,C#,.net,我只需要通过反射使用位于新域中指定文件中的.dll库。一切都很好,我可以获取信息、方法、类型,但当我实际想要调用其中一个方法时,会引发异常System.Reflection.TargetException(对象与目标对象不匹配)。问题是,当我将库“Filter.dll”的唯一名称设置为“path”并将库放在调试目录中时,应用程序就可以工作了。当我移动库并将其路径更改为@“D:/Dropbox/SchoolProject/MyPlugins/Filter.dll”时,会引发异常 我的代码: App

我只需要通过反射使用位于新域中指定文件中的.dll库。一切都很好,我可以获取信息、方法、类型,但当我实际想要调用其中一个方法时,会引发异常
System.Reflection.TargetException
(对象与目标对象不匹配)。问题是,当我将库“Filter.dll”的唯一名称设置为“path”并将库放在调试目录中时,应用程序就可以工作了。当我移动库并将其路径更改为@“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;
}          
AppDomain-domain=AppDomain.CreateDomain(“MyNewDomain”)//用于程序集的新域
//参数为@“D:/Dropbox/SchoolProject/MyPlugins/Filter.dll”、“Plugins.Filter”
ObjectHandle objh=domain.CreateInstanceFrom(_selectedLibraryDirections.Item1+_selectedLibraryDirections.Item2+“.dll”,_selectedLibraryDirections.Item3);
object obj=objh.Unwrap();
if(RemotingServices.IsTransparentProxy(obj))
{
类型domainType=null;
foreach(AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies()中的var ass)
{
//domainType的名称和全名为“Filter”,“Plugins.Filter”
//所以我认为这是我想要的类型,但例外是错误的
//使用方法的domainType时引发类型。调用
domainType=ass.DefinedTypes.First().AsType();
}
//类型的名称和全名为“Filter”,“Plugins.Filter”,
//当Filter.dll位于Debug dir中时,即使文件名位于
//domain.CreateInstanceFrom被设置为MyPlugins的路径,调用方法有效
//以及案例库中的“MarshalByRefObject”、“System.MarshalByRefObject”
//不在调试目录中,调用错误类型的方法时崩溃
Type Type=obj.GetType();
//按先前添加为ListBox项的方法名称获取方法
MethodInfo method=domainType.GetMethod(PluginMethodsListBox.SelectedItem.ToString());
//异常通常在调用时引发
Tuple Tuple=(Tuple)method.Invoke(域类型,新对象[]{“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);      
                            }

                        }
                    }
                }                    
            }      
foreach(库中的var库)
{
if(PluginsListBox.SelectedItem+“.dll”==library.Name)
{
//获取图书馆信息
Assembly ass=Assembly.ReflectionOnlyLoadFrom(library.DirectoryName+@“\”+library.Name);
var types=ass.GetTypes();
Type=null;
foreach(类型中的var t)
{
if(t.Name+“.dll”==library.Name)
{
_SelectedLibraryDirections=新元组(library.DirectoryName+@“\”,t.Name,t.FullName);
类型=t;
}
}
//查看列表框中的方法列表
if(type!=null)
{
PluginMethodsListBox.Items.Clear();
foreach(type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)中的MethodInfo方法)
{
if(method.ReturnType==typeof(Tuple)&&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);
    }
[可序列化]
公共类筛选器:MarshalByRefObject
{
public void noParamConsTest(){Console.WriteLine(“noparamconsoletest”);}
public void paramcontest(字符串s){Console.WriteLine(s);}
公共元组筛选器命令(字符串文本)
{
//..
返回新元组(returnString,string.Empty);
}
解决方案:

[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 working目录。从中加载程序集一点问题也并没有

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


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

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

Tuple<string, string> tuple = (Tuple<string, string>)method.Invoke(obj, new object[] { "hello" }); 
Tuple Tuple=(Tuple)方法。调用(obj,新对象[]{“hello”});

仅关于反射:

若要调用程序集的代码,请不要以仅反射模式加载程序集

将程序集加载到仅反射上下文中,可以在其中 已检查但未执行


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

即使我尝试这种方法,问题仍然存在。我需要为已加载的创建新域