2011-02-15 40 views
0

作为一个简单的例子,我有一个xml文件,其中包含实际执行工作的所有类的名称列表,以及所有使用Process()方法实现接口IDoWork的类。如何在运行时动态地将接口​​指向特定的类?

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

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

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

我想实现一个插件式的架构,除了插件是不是在汇编级只是我的程序中的一流水平。

+1

看看依赖注入。团结是一个好开始 – Luis 2011-02-15 14:19:51

+0

我推荐MEF为这个 – BrokenGlass 2011-02-15 14:23:06

回答

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

基本上,你有几种选择:

-Deserialize你的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() 

在国际奥委会的情况下,我会建议你使用AutoFacStructureMapCastle

+0

感谢你,我已经遇到过IoC,但我认为在这个简单而孤立的情况下,我可以使用正则反思。 – jaffa 2011-02-15 17:52:02

1

如果IDoWork是在同一组件DoWorkType1和DoWorkType2你可以这样做:

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

感谢更正大家!

+0

您需要提供Type.GetType()的全名,包括名称空间。 – jevakallio 2011-02-15 14:22:03

+0

不要忘了施放:-) – gsharp 2011-02-15 14:22:55

1

如果我理解你的问题,你应该用一个IoC容器相应的接口,像StructureMap注册不同的类,并用它来在运行时动态检索特定接口类型的对象。

1

是否有某个特定的原因,您不想使用numberdependencyinjectioncontainers这个?在他们的核心,这是他们所做的,为一个给定的接口注入一个基于某些配置/引导的实现。

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(); 
    } 
} 

我使用类似的方法在从数据库字段使用类名和创建的对象(S)在一个应用程序类似于上面使用工厂类的方式。这个简单的例子当然没有检查魔法字符串的错误,所以这将是一件值得注意的事情。

相关问题