我需要通过反射仅使用位于新域内指定文件中的.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,即使他们已经设置了自定义路径的基本路径,相对路径等,也会在默认工作目录中查找库而不是指定库或两者中的库。仅将自定义目录中的库加载到新域似乎对我来说是不可能的。
如果有人知道解释,请告诉我。谢谢
答案 0 :(得分:1)
您应该在实例obj
上调用该方法,而不是在domainType
类型上调用
Tuple<string, string> tuple = (Tuple<string, string>)method.Invoke(obj, new object[] { "hello" });
仅关于反思:
如果要调用其代码,请不要在仅反射模式下加载程序集。
将程序集加载到仅反射上下文中 检查但未执行。
使用常规Assembly.Load
方法之一。