2011-12-15 92 views
0

我有一些程序集和DLL的麻烦。从DLL实例化对象的调用方法

instrument_被声明为一个对象,并且我从路径由path_指定的dll创建了一个“PP150”实例。

string className = ContineoProperties.getSingleton().getClassName(path_); 
assembly_ = Assembly.LoadFrom(path_); 
Type classType = assembly_.GetType("Instrument." + className); 
instrument_ = Activator.CreateInstance(classType); 

后来我要调用的方法isntrument_.instrumentCommand(cmd.getCommandName())

我得到的错误是,当我调用该方法。

'对象' 中不包含关于 'instrumentCommand'

的isntrument_创建细的定义。它只是给我一个问题的方法调用。该方法确实存在于“PP150.dll”中。我是否需要一些DLLImport来允许它将它识别为一个函数?

感谢, P

+0

你看了看对象检查器中的程序集,看看有什么方法,属性等被暴露..? – MethodMan 2011-12-15 21:36:16

+0

对不起,我从来没有使用过对象检查器 我该如何检查它? – YahooMania 2011-12-15 21:39:15

回答

3

如果在编译时未知对象类型,则需要使用反射。

要调用在对象上定义的方法,必须使用反射。

MethodInfo mInfo = classType.GetMethod("instrumentCommand"); 

mInfo.Invoke(instrument_, new Object[] { _parameters}); 
+0

如果isntrumentCommand被重载? 我可以创建一个MethodInfo吗? And .Invoke()两次使用不同数量的参数? – YahooMania 2011-12-15 21:46:24

1

这是因为Activator.CreateInstance返回object。我将为您要实例化的类实现的interface创建单独的DLL。包含这个类的DLL和可执行文件都应该引用包含该接口的DLL。这样,您就可以通过Activator.CreateInstance投返回object的接口,并调用其方法:

IInstrument.dll:

interface IInstrument 
{ 
    void instrumentCommand(string cmd); 
} 

Instrument.dll(添加IInstrument.dll作为参考):

class Instrument : IInstrument 
{ 
    public void instrumentCommand(string cmd) 
    { 
    // ... implementation ... 
    } 
} 

InstrumentApp.exe(添加IInstrument.dll作为参考):

class Program 
{ 
    public static void Main() 
    { 
    // ... load Instrument.dll into assembly object ... 
    // ... load the type from the assembly ... 
    IInstrument instrument_ = (IInstrument)Activator.CreateInstance(classType); 
    instrument_.instrumentCommand(cmd.getCommandName()); 
    } 
} 
2

编译器是永远不会认识您正在经由反射胶片装入这样类型的方法(例如,使用Assembly.GetType()Activator.CreateInstance())。除非在构建时有类型元数据可用,否则如果尝试调用未在Object本身定义的方法,则将始终出现该错误。

您有两种选择来进行这种方法调用。他们都要求你放弃类型安全,唯一的区别就是所需的工作量。在这两种情况下,如果你犯了一个错误,编译器会而不是告诉你 - 你会得到一个运行时异常。

  1. 声明instrument_为dynamic而不是object。显然,这只适用于.NET 4.0,但它完成了你想要做的事情。该方法调用将在运行时分派,因此只要instrument_index 实例实际上具有的方法调用具有适当的名称,它就可以工作。

  2. 使用反射调用该方法。你已经在使用反射来加载类型,所以你已经到了一半。您将需要添加这样的事情:

    // The array of types is the parameter list; assuming instrumentCommand takes 
    // a string it would look like this: 
    MethodInfo method = classType.GetMethod("instrumentCommand", new Type[] { typeof(string) }); 
    method.Invoke(instrument_, new object[] { cmd.getCommandName() }); 
    
1

最简单的事情将是agains PP150链接。

如果你没有链接到dll,你必须使用Assembly.LoadFile或Assembly.Load而不是LoadFrom,因为最后一个会导致程序集加载在LoadFrom加载器上下文中加载你的程序集,这将改变类型标识。 假设您通过LoadFrom从程序集A加载类型T,并且您也与A链接。

object CreateTypeFrom() 
{ 
    var A = Assembly.LoadFrom(@"xxxx"); 
    return A.CreateInstance("T"); 
} 

void Test() 
{ 
    object t = CreateTypeFrom(); 
    T RealT = new T(); // no prob 
    T Castedt = (T)t; // this will throw an InvalidCastException 
    T isNull = t as T; // this will result in a null instance 
} 

正如你可以看到,虽然你没有创建两个时间T的一个实例,它们不能被强制转换为由于不同的加载器上下文,这将使类型好看不中用。

要摆脱这些事情,您可以简单地使用反射来创建一个代理类型,将您的调用转发到代理类型。如果您使用.NET 4,则可以利用DLR在运行时查找最佳匹配方法。下面的代码创建一个Version对象并将其作为动态对象返回。然后我将Major属性调用为一个整数并将其输出到控制台。如果您使用的是.NET 4或更高版本,这确实没有例外,也不会编译时间错误。

 dynamic CreateTypeFrom() 
     { 
      var assembly = typeof(string).Assembly; 
      return assembly.CreateInstance("System.Version", true, BindingFlags.CreateInstance, null, new object[] { 1, 2, 3, 4 }, null, null); 
     } 

     [TestMethod] 
     public void Test() 
     { 
      var t = CreateTypeFrom(); 
      int major = t.Major; 
      Console.WriteLine(major); 
     }