如何在运行时动态地将接口​​指向特定类?

时间:2011-02-15 14:15:22

标签: c# .net xml

作为一个简单的例子,我有一个xml文件,其中包含实际执行工作的类名称列表,并且所有类都使用方法Process()实现接口IDoWork。

我循环遍历xml文件中的项目。 如何从字符串名称实际动态地将类分配给接口? e.g。

var IDoWork = new "DoWorkType1"();
IDoWork.Process();

<work>
  <item id="DoWorkType1">
  </item>
  <item id="DoWorkType2">
  </item>
</work>

我想实现一个插件类型的体系结构,除了插件不是程序级别只是程序中的类级别。

6 个答案:

答案 0 :(得分:3)

Type t = Type.GetType("DoWorkType1");
IDoWork idw = (IDoWork)Activator.CreateInstance(t);
idw.Process();

答案 1 :(得分:1)

基本上,您有几种选择:

- 将xml反序列化为IDowork类的集合。并在每个上执行Process方法。

- 使用Activator.CreateInstance手动创建对象。

- 使用一些 IoC 框架。然后,您将在应用程序启动时注册所有插件,并在IoC将构建的实例上执行您的操作。这样的事情。

//On Application Start
Container.Register("DoWorkType1", typeof(DoWorkType1));
Container.Register("DoWorkType2", typeof(DoWorkType2));

//Execute your actions
var instance = Container.Resolve<IDowork>("DoWorkType2");
instance.DoWork()

如果是IoC,我建议您使用AutoFacStructureMapCastle

答案 2 :(得分:1)

如果IDoWork与DoWorkType1和DoWorkType2在同一个程序集中,您可以这样做:

Type t = typeof(IDoWork).GetAssembly().GetType("DoWorkType1");
IDoWork w = (IDoWork)Activator.CreateInstance(t);
w.Process();

感谢大家的纠正!

答案 3 :(得分:1)

如果我理解你的问题,你应该用IoC容器(如StructureMap)注册你的各种类,并使用它来在运行时动态检索特定接口类型的对象。

答案 4 :(得分:1)

是否有特定原因您不想使用number dependency injection containers中的任何一个?他们的核心是他们真正做的事情,根据一些配置/引导为一个给定的接口注入一个实现。

答案 5 :(得分:0)

抱歉,决定做一个快速的例子(掀起一个控制台应用程序):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Interfaces;
using Classes;


namespace Interfaces
{
    public interface IDoWork
    {
        string Name { get; set; }
        string Process();
    }
}

namespace Classes
{
    public class FactoryClass
    {
        private static readonly IDictionary<string, Type> ClassMembers 
            = new Dictionary<string, Type>();
        public static T Create<T>(string s) where T : class
        {
            // if we have 'cached' the type, then use it
            if (ClassMembers.ContainsKey(s))
            {
                return (T)Activator.CreateInstance(ClassMembers[s]);
            }
            // determine the concrete type
            var concreteClass = Assembly.GetExecutingAssembly()
                .GetTypes()
                .Where(t => typeof(T).IsAssignableFrom(t)
                    && t.FullName.ToLower().Contains(s.ToLower()))
                .FirstOrDefault();
            // if we have a match - give it a ping...
            if (concreteClass != null)
            {
                var newUnit = (T) Activator.CreateInstance(concreteClass);
                ClassMembers.Add(s, concreteClass);
                return (T) newUnit;
            }
            // for the sake of the example - return null for now
            return null;
        }
    }

    public class DoWorkType1 : IDoWork
    {
        public string Name { get; set; }
        public bool isNew = true;
        public string Process()
        {
            isNew = false;
            return "It's me - Mr DoWorkType1";
        }
    }

    public class DoWorkType2 : IDoWork
    {
        public string Name { get; set; }

        public string Process()
        {
            return "My turn - Ms DoWorkType2";
        }
    }
}

class Program
{
    public static void Main(string[] args)
    {

        var newWork = FactoryClass.Create<IDoWork>("DoWorkType1");
        Console.WriteLine(newWork.Process());
        newWork = FactoryClass.Create<IDoWork>("DoWorkType2");
        Console.WriteLine(newWork.Process());
        // repeat with DoWorkType1 just to show it coming from dictionary
        newWork = FactoryClass.Create<IDoWork>("DoWorkType1");
        Console.WriteLine(newWork.Process());
        Console.Read();
    }
}

我在一个应用程序中使用类似的方法,该应用程序从数据库字段获取类名,并使用工厂类以与上面类似的方式创建对象。这个简单的例子当然没有检查魔术字符串拼写错误,所以这是一个需要注意的附加内容。