C#: 泛型继承工厂

3

我有一个基类,它只有一个通用参数。然后我有几个继承自这个基类的类。子类是否有一种简单的方式可以从基类继承工厂?

示例

class BaseClass<T>
{
     T Value {get; set;}
     string Name {get; set;}

     public static BaseClass<T> Factory(T Value)
     {
        return new BaseClass<T>(Value); 
     }
}

class ChildClass : BaseClass<int>
{
     public void Test()
     {
         // I want this below to work
         // but Factory() returns a BaseClass
         ChildClass bs = ChildClass.Factory(10);
     }
}

我已经在代码中注明了我的意图。我能想到一种克服这个问题的方法,就是在BaseClass或SubClass中添加一个隐式转换运算符,将BaseClass转换为ChildClass。

我也可以直接将工厂添加到ChildClass,但这违背了继承的目的。

有没有更好、更标准的方法来解决这个问题呢?


为什么不直接在 Test() 函数内进行类型转换? - Alastair Pitts
1
我不想让类需要强制转换来实现功能。如果我要进行转换,我会将其变为隐式转换。 - Mike
4
Factory()应该声明为静态的吗? - Mark Cidade
@Mark:很可能。是的。不过我并不在意,我不想让它妨碍更细致的回答。 - Mike
您的Factory方法被声明为实例方法,但被使用时却像静态方法。 - Ani
2个回答

8
我会这样做:
class BaseClass<T, K> where K : BaseClass<T, K>, new()
{
    T Value { get; set; }
    string Name { get; set; }

    public static K Factory(T value)
    {
        return new K { Value = value };
    }
}

class ChildClass : BaseClass<int, ChildClass>
{
    public void Test()
    {
        ChildClass cs = Factory(10);
    }
}

它无法编译,因为编译器无法推断出ChildClass,更不用说您没有指定BaseClass了。在您的代码中,应该是BaseClass<int, ChildClass>.Factory(10) - Kobi
1
@Kobi:它可以编译。我经常在通用继承层次结构中这样做。 - siride
@siride - 你说得对,我错过了Factory被继承的部分。糟糕(奇怪的是,我记得测试它:P)。虽然它会改变类的签名,但似乎非常好用,如果你调用ChildClass.Factory(1),所以也许这并不重要。 - Kobi
@Mike:这是一种奇特的递归模板模式(CRTP)。基类完成所有工作,类型信息通过从更具体的子类继承传递。Eric Lippert反对它,但我不同意他的立场和理由。 - siride
反对这种方法的一个原因是,仍然可以说class ChildClass:BaseClass<int,OtherClass>,并且在BaseClass内部为OtherClass创建一个工厂。 - Mark Cidade
显示剩余2条评论

0

很难回答你的问题,因为你描述了你想做什么,但没有说出为什么。所以我得猜测你的意图。

我不会把工厂方法放在同一个类中,就像其他答案或你的问题一样。你如何处理继承?它适用于你拥有的两个级别。但是如果你想扩展ChildClass怎么办?

相反,我会创建一个通用工厂用于对象创建。将其实现为包装在工厂接口周围的单例,以便轻松扩展或交换实现。

class MyFactory
{
    private static IMyFactory _instance;
    public static void Assign(IMyFactory factory) { _instance = factory; }
    public static T Create<T>() { return _instance.Create<T>(); }
}

interface IMyFactory
{
    T Create<T>();
}
class MyFactoryImp : IMyFactory
{
    //do whatever needed in here
    public T Create<T>(){ return new T(); }
}


class BaseClass<T>
{
     T Value {get; set;}
     string Name {get; set;}
}

class ChildClass : BaseClass<int>
{
     public void Test()
     {
         ChildClass bs = MyFactory.Create<ChildClass>(10);
     }
}

// start with this, you can easily switch implementation
MyFactory.Assign(new MyFactoryImp());

另一个显而易见的答案是开始使用控制反转容器,例如autofac。

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