我使用反射从另一个dll调用一个方法。该方法将一个类对象作为输入。我怎么称呼这种方法。 我尝试将同一个类复制到两个dll,然后创建了该类的对象并传递它。它会在complie time本身中引发invliad转换错误。 然后我试着让函数将一个对象作为参数,然后尝试将它转换为所需的类。它在运行时抛出无效的强制转换异常。 这就是我试过的
Test objTest = new Test("name","type");
Assembly assembly = Assembly.Load("MyProject.Components");
Type dllType = assembly.GetType("MynameSpace.MyClass");
if (dllType != null)
{
MethodInfo m = dllType.GetMethod("MyFunction");
object objdll;
objdll = Activator.CreateInstance(dllType);
object[] args = { objTest };
if ((m != null))
{
strReturnValue += (string)m.Invoke(objdll, args);
}
}
在第二个dll中,方法就像
public string MyFunction(Test obj)
我的问题是班级考试在 另一个集会(班级在 两个不同的组件)
答案 0 :(得分:1)
你有一点设计问题。您有一个程序集(让我们称之为程序集A),其中包含您发布的示例反射代码。你还有第二个程序集(我们称之为程序集B),它包含MyClass和Test。
问题在于,在您的反射代码中,您正在尝试创建Test类的实例,以便您可以将其作为参数传递给MyClass.MyFunction。
您提到您已将Test类的源代码复制到程序集A中;那样不行。你在那里做的基本上是创建两个具有相同名称和相同结构的不同类。由于这两个类在CLR方面并不相同,如果你试图将一个类转换为另一个,你将得到一个无效的强制转换异常。
鉴于您到目前为止发布的内容,在我看来,您的方法最直接的解决方案是让第三个程序集(让我们称之为程序集C)包含程序集A和B都知道的组件。在解决方案中创建一个类库项目,将Test类移动到该项目中,在前两个项目中删除Test类的任何其他实例,并在引用新项目的前两个项目中添加引用。完成后,程序集A和程序集B将引用Test类的相同类定义,并且您发布的示例代码将起作用。
让我指出一些事情。如果程序集A中的代码对程序集B中的代码知之甚少,以便实例化MyClass并直接调用MyFunction(而不是通过反射),那么它如何充分了解该代码以了解要传递的参数? MyFunction是否具有程序集A理解的通用方法签名?如果是这种情况,那么MyClass应该实现程序集A知道的接口,以便程序集A可以直接调用MyFunction,如下所示:
Assembly assembly = Assembly.Load("MyProject.Components");
Type dllType = assembly.GetType("MynameSpace.MyClass");
if (dllType != null)
{
IMyInterface instance = Activator.CreateInstance(dllType) as IMyInterface;
if (instance != null) // check if this object actually implements the IMyInterface interface
{
instance.MyFunction(objTest);
}
}
如果这似乎不是您想要的方法,那么还有其他选择。由于您似乎不希望程序集A直接引用程序集B,如果将Test类保留在程序集B中,那么程序集A没有任何方法可以了解Test类的任何知识为了构建一个。在这种情况下,您可以使用工厂模式方法,基本上使组件A知道某种能够实例化Test对象的工厂对象。以下是一个实现示例:
我上面提到过创建第三个项目。我仍然会建议这样做。在我的例子中,我将我的名字命名为“MyProject.Common”。它包含以下代码:
// define a simple factory interface
public interface IFactory
{
object CreateInstance();
}
// and a generic one (hey, why not?)
public interface IFactory<T> : IFactory
{
new T CreateInstance();
}
// define a Factory attribute that will be used to identify the concrete implementation of a factory
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
public class FactoryAttribute : Attribute
{
public Type FactoryType { get; set; }
public FactoryAttribute(Type factoryType)
{
this.FactoryType = factoryType;
}
}
我的解决方案中的其他项目将知道并理解IFactory接口和Factory属性,因为它们都引用了MyProject.Common项目。
以下是我的“MyProject.Components”项目中包含的代码:
public class Test
{
public string Name { get; set; }
public string Type { get; set; }
public Test(string name, string type)
{
this.Name = name;
this.Type = type;
}
}
public class TestFactory : IFactory<Test>
{
#region IFactory<Test> Members
public Test CreateInstance()
{
return new Test("name", "type");
}
#endregion
#region IFactory Members
object IFactory.CreateInstance()
{
return this.CreateInstance();
}
#endregion
}
public class MyClass
{
// the Factory attribute on the first parameter indicates that the class TestFactory
// should be used as a factory object to construct the argument for this method
public string MyFunction([Factory(typeof(TestFactory))]Test obj)
{
if (obj == null)
return null;
else
return obj.ToString();
}
}
最后,我用以下内容替换了您发布的原始反射代码:
Assembly assembly = Assembly.Load("MyProject.Components");
Type dllType = assembly.GetType("MynameSpace.MyClass");
if (dllType != null)
{
MethodInfo m = dllType.GetMethod("MyFunction");
object objdll;
objdll = Activator.CreateInstance(dllType);
// use the parameter information to construct the arguments
ParameterInfo[] parameters = m.GetParameters();
object[] args;
if (parameters != null && parameters.Length > 0)
{
args = new object[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
// check for factory attributes on the actual parameter
FactoryAttribute[] attributes = parameters[i].GetCustomAttributes(typeof(FactoryAttribute), true) as FactoryAttribute[];
// if no attributes were found, check the parameter type for factory attributes
if (attributes == null || attributes.Length == 0)
attributes = parameters[i].ParameterType.GetCustomAttributes(typeof(FactoryAttribute), true) as FactoryAttribute[];
// if no attributes were found still, then give up
if (attributes == null || attributes.Length == 0)
{
// this parameter has no factory specified,
// so how would this code know how to create the argument for that parameter ???
args[i] = null;
continue; // move on to the next parameter
}
// there should only be one factory attribute, so use the first one
// assumption made here is that all factory classes will have a parameterless constructor
IFactory factory = Activator.CreateInstance(attributes[0].FactoryType) as IFactory;
args[i] = factory.CreateInstance();
}
}
else
// there are no parameters
args = null;
if ((m != null))
{
strReturnValue += (string)m.Invoke(objdll, args);
}
}
答案 1 :(得分:0)
如果你的对象是一个Type
对象的对象,那么你可以只传递对象的类型作为参数......例如。
object[] args = {typeof(typeneeded)};
或
object[] args = { assembly.GetType(typeneeded) };
答案 2 :(得分:0)
MethodInfo.Invoke()
声明如下:
public Object Invoke(
Object obj,
Object[] parameters
)
第一个参数指定要处理的对象,第二个参数指定函数的参数。
我在LINQPad中复制了你的代码,这很好用:
void Main()
{
string strReturnValue = "";
Test objTest = new Test("name","type");
Type dllType = typeof(MyClass);
if (dllType != null)
{
MethodInfo m = dllType.GetMethod("MyFunction");
object objdll;
objdll = Activator.CreateInstance(dllType);
object[] args = { objTest };
if ((m != null))
{
strReturnValue += (string)m.Invoke(objdll, args);
}
}
}
public class Test
{
public Test(string s1, string s2)
{
}
}
public class MyClass
{
public string MyFunction(Test t)
{
return "";
}
}
您必须以加载MyClass实例的方式加载Test对象,并且由于Test需要在构造函数中使用参数,您必须使用ConstructorInfo:
Assembly assembly = Assembly.Load(); //assembly of "Test"
Type testType = assembly.GetType("Test");
ConstructorInfo ci = testType.GetConstructor(
BindingFlags.Public | BindingFlags.Instance,
null,
new Type[]{typeof(string), typeof(string)},
null);
Test objTest = ci.Invoke(new object[] { "name", "type" });
现在您可以在代码中使用objTest
。