工厂模式使用反射 - 使用与每个类关联的静态键进行类注册

Him*_*ere 2 c# reflection factory-pattern

在研究某些模式时,我遇到了工厂模式,以创建(未知)类的实例.这让我感兴趣,因此我想构建一个可以动态增强的程序.所以我在一个程序集中有一些基本功能,在不同程序集中有实际的工作程序.我从应用程序中获得的唯一提示是操作名称.现在我想创建一个依赖于该操作的新工作者.因为我不知道工人的实际实施,所以我选择了这种模式.

好的,更多细节:

我有一个接口IWorker,我的所有流程都实现了.Singleton WorkerFactory允许我创建在与当前路径相同的路径中的任何程序集中实现的任何worker的新实例.为此,我CreateWorker在我的接口中添加了一个接受字符串数组的方法(已经传递varargs给控制台应用程序).

在能够创建任何工人的任何实例之前,我必须将任何类注册到工厂.不幸的是在C#这是不可能静态地插入这样的行为变成了工人类的任何静态情况下,因为这个范围内的代码才会执行上课的时候以任何方式访问(通过实例,或通过访问任何的吧它的静态成员,请参阅静态构造函数).因此,我通过使用当前正在执行的程序集的路径反映所有程序集中找到的所有类型来实现此目的.现在我可以检查当前类型是否正在实现接口,如果是,则可以将类型添加到包含操作名称(键)和工作者(值)的工厂的注册图中System.Type(参见使用反射的工厂模式).问题是:如何获取此类型引用的操作的实际名称.

我认为有两种选择:

  1. 我向每个存储操作名称的worker-class添加一个静态属性.因此,我可以通过在获得的类型上反映此属性来引用该操作.
  2. 为名称添加非静态属性,并在注册时创建实际worker类的虚拟实例.

前者选项的缺点是,我不能保证所有的工人居然有这样的静态属性实现的(因此它无法静态成员添加到IWorker接口),后者每一个类必须有一个空的缺点构造函数,以便构建从中获取操作名称的虚拟实例.然而,这个构造函数可以公开访问,而不包含任何初始化代码.

说完所有这些问题都是关于使用反射的工厂模式的最佳或至少更好的实践.我想我更喜欢第一种选择,但也许我也错过了这种方法的更好的解决方案.

因此这个帖子已经很长了我不想在这里发布任何代码,但是如果你需要的话请告诉我.

Eug*_*kal 5

您可以在工作类上使用自定义属性:

[AttributeUsage(System.AttributeTargets.Class)]
public class WorkerAttribute : Attribute
{
    public WorkerAttribute (String operationType)
    {
       this.OperationType = operationType; 
    }

    public String OperationType {get; private set;}
}

public interface IWorker { }

[WorkerAttribute("Experienced")]
public class ExperiencedWorker: IWorker
{
}
Run Code Online (Sandbox Code Playgroud)

它们的访问方式与此处描述的相同.它将是这样的:

       Type attributeType = typeof(WorkerAttribute);

        var myWorkerClassesPlusAttributes = from assembly in AppDomain.CurrentDomain.GetAssemblies()
                                            from type in assembly.GetTypes()
                                            let attributes = type.GetCustomAttributes(attributeType, true)
                                            where attributes.Any()
                                            select 
                                                new KeyValuePair<String, Type>(((WorkerAttribute)attributes.First()).OperationType, 
                                                                               type);

        Dictionary<String, Type> workers = new Dictionary<string, Type>();
        foreach (var item in myWorkerClassesPlusAttributes)
            workers.Add(item.Key, item.Value);

        IWorker worker = (IWorker)Activator.CreateInstance(workers["Experienced"]);
Run Code Online (Sandbox Code Playgroud)

它不是最好的,并且不包括类中的多个WorkerAttributes,但可以用作解决方案的基础.