【问题标题】:C# structure of generic factory for multiple derived classes多个派生类的泛型工厂的C#结构
【发布时间】:2013-01-09 19:53:36
【问题描述】:

考虑以下情况:

可以有CategoriesChildren 派生自 Categories;在某个地方,必须有一个看起来像这样的方法:

ChildType[] Get(ParentType parent) { ... }

ChildType 不是从ParentType 派生的;之所以这样命名,是因为该方法是一种工厂方法,用于根据父母的 ID 获取孩子。

目前我有这样的东西:

static class CatFactory<ChildType, ParentType> : Category
    where ParentType: Category
    where ChildType: Category, new()
{
    public static ChildType[] Get(string catname, ParentType parent)
    {
        // ...
    }
}

class ParentCategoryA : Category { }

class ParentCategoryB: Category { }

class ChildCategoryA: Category { }

class ChildCategoryB: Category { }

然后我会这样调用工厂:

CatFactory<ChildCategoryA, ParentCategoryA>.Get(someparent);

这样做的目的是 - 给定一些具有 ID 的强类型父实例,转到具有该 ID 的 Web 服务,然后反序列化一个新的子实例。

这在我嘴里留下了不好的味道。在我看来ChildCategoryA 应该知道它的父级是ParentCategoryA,并且应该能够调用ChildCategoryA.Get(someparent)。这当然可以通过为孩子的每个实现定义一个static Get() 来实现,但这需要大量的重复代码。

那么 - 最好的方法是什么?单独的工厂类,还是没有?

【问题讨论】:

  • 你能定义一个通用的Category&lt;TParentType&gt;吗?所以你会有class ChildCategoryA : Category&lt;ParentCategoryA&gt;? (反过来,Category&lt;TParentType&gt; 可能继承自非泛型 Category 基类,如果它对您的 API 有意义)
  • 不能有Category&lt;TParentType&gt;,因为有些类别没有父级。但是,我可以有类似ChildCategory&lt;TParentType&gt; 的东西。但我不知道这会让我走多远——我怎么会有一个static Get()
  • 您可以定义一个密封的内部构造函数RootCategory 类型作为虚拟对象来指示根类别。至于Get... uhhhh 井类型可以在第一次使用时注册自己(静态构造函数)?或者您可以通过应用程序启动时的反射进行搜索以找到所有类型?
  • 我认为public static ChildType[] Get(string catname) 会是一个更简洁的签名。 ParentType 将从 CatFactory 的类型中推断出来。 (我没有方便的编译器来测试这个。)
  • @neontapir Get() 需要传递一个父实例来获取一个子实例。它不仅取决于父级的类型,还取决于父级字段之一的值。

标签: c# oop generics


【解决方案1】:

我觉得这个问题有点令人困惑。这就是我认为你想要做的:

编写一个静态方法,给定一个 Category 对象,该方法知道如何查找指定类型的该类别的所有子项。

如果正确,那么我会建议一种扩展方法:

static class CategoryExtensions
{
    public static T[] GetChildren<T>(this Category parent)
        where T : Category, new()
    {
        // Do whatever...
    }
}

然后,给定任何类别对象,您可以这样写:

ChildCategory[] children = parent.GetChildren<ChildCategory>();

【讨论】:

  • 但是您可以在 ParentCategoryA 类型的父实例上调用 parent.GetChildren(),即使不存在此子类与这样的父类关联的情况。在这种情况下,语义可能只是不返回任何内容,但开发人员可能希望得到一个编译时错误。
  • 这当然是可能的。我确实说过这个问题令人困惑。 ;) 然而,鉴于 OP 中的代码示例,他似乎想在任意类型对上定义 GetChildren() 操作。
  • 在理想情况下,不应该支持任意pair类型,因为给定一个特定的孩子,它只有一个有效的父类型。
  • @PeterRuderman 如果可以按照 CSharper 的建议进行操作,并在类型对不匹配时出现编译时错误 - 你有什么建议去做吗?
  • 这当然是可能的,但此时我们开始讨论更基本的重新设计。如果不详细了解您要达到的目标,就很难知道该建议什么。您不使用 WCF 之类的框架是否有某些原因?
【解决方案2】:

一个想法是在运行时使用反射来定位所需的类型。这很慢,通常不推荐;如果这样做,明智的做法是缓存结果以避免多次反映。

不涉及反射的另一种方法是让孩子将自己添加到静态初始化程序中的某种注册表 - 这样您就可以轻松编写所需的 Get&lt;TChild, TParent&gt; 方法,同时保持“本地”关系的知识。

就个人而言,如果在编译时就知道所有这些关系,我只需将它们全部连接到一个地方,就可以省去记住所有定义的位置的麻烦。 =)

【讨论】:

    猜你喜欢
    • 2018-01-08
    • 2020-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多