2015-07-19 76 views
1

有几个程序我见过,但我不确定我知道它叫什么。从本质上讲,他们将采取各种类:C#控制反转 - 获取实例化基类的所有类

Class1的

的Class2

Class3的

这些类具有可变也许叫做顺序或步数:

[IClassBaseRunner] 
public Class1 : IClassBase 
{ 
    public int step{ get { return 10; } } 
... 

[IClassBaseRunner] 
public Class1 : IClassBase 
{ 
    public int step{ get { return 30; } } 
... 

[IClassBaseRunner] 
public Class1 : IClassBase 
{ 
    public int step{ get { return 20; } } 
... 

所有这些类都是IClassBase之类的接口的一部分。现在,他们可以做一些他们不需要初始化任何类的东西,但是每个类都必须在类的声明之上有一个属性,例如[IClassBaseRunner]。所有这些都可以实现,它将运行它们的所有组件,而不需要单独实例化。他们会将每个类添加到列表中,然后按顺序执行这些步骤。如果添加了第4步,所有你所要做的就是添加一行类的初始化上面,有点像它在命名空间,如下所示:

[IClassBaseRunner] 
public Class4 : IClassBase 

我不知道其所谓的,但是如果有人有任何关于它的信息或要搜索什么,那就太好了。它与控制和属性的倒置有关。

谢谢!

+0

好了,你可以搜索 “依赖注入” 的一个开始 –

回答

0

我不能肯定你正在说明的确切模式,但它似乎至少落入基本策略模式。

根据您提到的无需实例化类或在包含新类时添加boostraping代码...这是一种良好的依赖注入库和基于约定的策略可以提供的帮助。添加某种程序集扫描,你几乎不必处理配置组件。

下面是使用Ninject和Ninject惯例扩展(Nuget package ninject.extensions.conventions)可以实现的一个例子。这个例子并不需要你的问题所示的任何属性装饰器,但是如果你需要的话,你可以创建和使用它们。

此外,结构图和MEF是其他流行的依赖注入库,您可以尝试使用并查看哪些最适合您。

static IKernel kernel = new StandardKernel(); 
void Main() 
{ 
    // 
    // Automatic binding using 
    // Ninject.Extensions.Conventions 
    // Generally, you only want to declare your 
    // DI container once in the application lifetime 
    // Expecially in web apps, you will also need to 
    // consider the scope of bound classes, such as: 
    // Transient, Thread, Singleton, or Request 
    kernel.Bind(x=>x 
     .FromThisAssembly() 
     .SelectAllClasses() 
     .BindAllInterfaces() 
    ); 
    // 
    // Now we can resolve the loader and run it 
    // Compare this code to how it would look if you 
    // manually instantiate all the dependencies and consider: 
    // - How much additional code is there? 
    // - How easy is it to perform unit tests on the various 
    // components (Mocking is useful here)? 
    // - What is the effort if I need to swap out a service 
    // such as IMessageWriter? 
    // 
    // IMPORTANT: For example only. Do not use kernel.Get() 
    // all over your code base. 
    // This results in a ServiceLocator anti-pattern! 
    ProcessRunner runner = kernel.Get<ProcessRunner>(); 
    runner.Execute(); 
} 

public interface IMessageWriter{ 
    void Write(string message); 
} 

public class MessageWriter : IMessageWriter 
{ 
    public void Write(string message){ 
     Console.WriteLine ("MESSAGE: {0}", message); 
    } 
} 

public interface IProcessStep { 
    int Step{ get; } 
    void Execute(); 
} 

public class ProcessRunner 
{ 
    private readonly IEnumerable<IProcessStep> steps; 
    public ProcessRunner(IEnumerable<IProcessStep> steps) 
    { 
     this.steps = steps;  
    } 

    public void Execute(){ 
     steps 
      .OrderBy (o => o.Step) 
      .ToList() 
      .ForEach(i=>i.Execute()); 
    } 
} 
public class ProcessStep1 : IProcessStep 
{ 
    private readonly IMessageWriter writer; 
    public ProcessStep1(IMessageWriter writer) 
    { 
     this.writer = writer;  
    } 
    public int Step { get { return 10; }} 
    public void Execute(){ 
     writer.Write("Hello from step1!");  
    } 
} 
public class ProcessStep2 : IProcessStep 
{ 
    private readonly IMessageWriter writer; 
    public ProcessStep2(IMessageWriter writer) 
    { 
     this.writer = writer;  
    } 
    public int Step { get { return 20; }} 
    public void Execute(){ 
     writer.Write("Hello from step2!"); 
    } 
} 
public class ProcessStep3 : IProcessStep 
{ 
    private readonly IMessageWriter writer; 
    public ProcessStep3(IMessageWriter writer) 
    { 
     this.writer = writer;  
    } 
    public int Step { get { return 30; }} 
    public void Execute(){ 
     writer.Write("Hello from step3!"); 
    } 
} 

输出

MESSAGE: Hello from step1! 
MESSAGE: Hello from step2! 
MESSAGE: Hello from step3!