工厂类返回一个通用接口

14

我有几个使用以下接口类型的具体内容:

interface IActivity<T>
{
    bool Process(T inputInfo);
}

具体类如下所示。
class ReportActivityManager :IActivity<DataTable>
{
    public bool Process(DataTable inputInfo)
    {
        // Some coding here
    }
}

class AnalyzerActivityManager :IActivity<string[]>
{
    public bool Process(string[] inputInfo)
    {
        // Some coding here
    }
}

现在我应该如何编写工厂类以返回一个通用接口,例如IActivity?
class Factory
{
    public IActivity<T> Get(string module)
    {
        // ... How can i code here
    }
}

谢谢


获取错误... 错误 CS0050:不一致的可访问性:返回类型 - Anish
2个回答

17

你应该创建一个通用方法,否则编译器将不知道返回值中的T类型。当你有了T,你就可以基于T的类型创建活动:

class Factory
{
    public IActivity<T> GetActivity<T>()
    {
        Type type = typeof(T);
        if (type == typeof(DataTable))
            return (IActivity<T>)new ReportActivityManager();
        // etc
    }
}

使用方法:

IActivity<DataTable> activity = factory.GetActivity<DataTable>();

我遇到了一个错误:“error CS0050:不一致的可访问性:返回类型”。 - Anish
它可以正常工作...但是我想知道为什么当我将类设为public时,会抛出错误...所抛出的错误是Inconsistent accessibility: return type Factory.Managers.IActivityManager<T>' is less accessible than method 'Factory.Managers.Factory.GetActivity<T>()' 。 - Anish
@Anish 欢迎 :) 顺便考虑使用依赖注入框架。例如,使用 ninject,您可以这样绑定您的管理器 Bind<IActivity<DataTable>>().To<ReportActivityManager>(); 然后以这种方式检索实例:IActivity<DataTable> activity = kernel.Get<IActivity<DataTable>>(); - Sergey Berezovskiy
这绝对看起来像是服务定位器。这里有一篇博客文章,解释了抽象工厂和服务定位器之间微妙的区别。 - Sean
@Sean 谢谢,好链接。同意,这个API看起来像服务定位器。此外,我想补充一点工厂和服务定位器之间的一个重大区别,这在帖子中没有提到 - 通常(甚至总是)工厂创建新对象,并且它们有称为“Create”的方法。另一方面,服务定位器只是定位服务所在的位置并返回对服务的引用。也就是说,如果我们使用单例,则应用程序将使用服务的单个实例。这就是为什么服务定位器通常具有名为“Get”的方法而不是“Create”的原因,因为这会让人感到困惑。 - Sergey Berezovskiy
显示剩余2条评论

1
通常这是通过 lazyberezovsky's answer 实现的。在 C++ 中,您可以使用模板特化来在尝试创建工厂不处理的类型时获得编译器错误。
在 C# 中无法做到这一点,但可以接近实现。虽然代码可能看起来有些令人惊讶,这可能会成为一个问题。
public static class Factory {
   public static IActivity<someType> Get(this someType self){
          //stuff specific to someType
   }

   public static IActivity<someOtherType> Get(someOtherType self){
          //stuff specific to someOtherType
   }

   public static T Creator<T>(){
        return null;
   }

}

使用情况将会是

IActivity<someType> act = Factory.Creator<someType>().Get(); 

当然,这仅适用于您可以传递具体类型的情况。如果您需要传递类型参数,则情况会变得更加复杂。


我对C#不是很擅长,但第二个方法不是扩展方法只是一个疏忽吗? - Asad Saeeduddin
另外,关于“您可以使用模板特化来在尝试创建工厂不处理的类型时获得编译器错误”,您是否可以使用类型约束来在工厂处理不想处理的类型时获得编译器错误? - Asad Saeeduddin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接