如何实例化一个未包含在C#项目中的对象?

时间:2011-02-09 00:35:00

标签: c#-4.0 manifest late-binding

注意:所有示例代码都大大简化了。

我有一个DLL定义为:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Web;

namespace RIV.Module
{
    public interface IModule
    {
        StringWriter ProcessRequest(HttpContext context);
        string Decrypt(string interactive);
        string ExecutePlayerAction(object ParamObjectFromFlash);
        void LogEvent(object LoggingObjectFromFlash);
    }
}

现在,在我的解决方案之外,其他开发人员可以定义具体的类并将它们放入我的应用程序的BIN文件夹中。也许是这样的:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RIV.Module;

namespace RIV.Module.Greeting
{
    public class Module : IModule
    {
        public System.IO.StringWriter ProcessRequest(System.Web.HttpContext context)
        {
            //...
        }
        public string Decrypt(string interactive)
        {
            //...
        }
        public string ExecutePlayerAction(object ParamObjectFromFlash)
        {
            //...
        }
        public void LogEvent(object LoggingObjectFromFlash)
        {
            //...
        }
    }
}

现在,在我的应用程序中,我需要知道有一个新模块可用(我猜测是通过web.config或其他类似的东西),然后能够根据数据库Campaign表中的某些触发器调用它(映射到用于该特定广告系列的模块)。

我试图以这种方式实例化它:

var type = typeof(RIV.Module.Greeting.Module);
var obj = (RIV.Module.Greeting.Module)Activator.CreateInstance(type);

但是,编译器因为从未将引用设置为 RIV.Module.Greeting.dll 而打嗝!

我做错了什么?

2 个答案:

答案 0 :(得分:2)

您需要使用更多反射:

  • 通过调用Assembly.Load
  • 加载程序集
  • 通过调用someAssembly.GetType(name)或搜索someAssembly.GetTypes()
  • 来查找类型
  • Type个实例传递给Activator.CreateInstance
  • 将其投射到您的界面。

答案 1 :(得分:1)

取代typeof(RIV.Module.Greeting.Module),尝试使用

var type = Type.GetType("RIV.Module.Greeting.Module, RIV.Module.Greeting");

(即通过将其程序集限定的名称指定为字符串来加载类型)并转换为IModule。

这种方法要求您知道模块的确切类和程序集名称(如您所写,它们可以存储在web.config中)。

或者,您可以采用完全动态的插件方法:

  1. 建立一个约定,所有模块程序集都应命名为“RIV.Module.XYZ”
  2. 扫描bin目录以查找匹配的DLL
  3. 为每个DLL加载它(例如Assembly.Load)并扫描实现IModule的类型
  4. 实例化所有找到的类型并转换为IModule