【问题标题】:Casting, Generics, and Subtypes强制转换、泛型和子类型
【发布时间】:2011-02-17 21:17:57
【问题描述】:

在尝试实现存储库模式时,我遇到了一个小问题,我担心它实际上掩盖了更大的问题。

我有一个 DatabaseEntity<T>,我用它来处理所有基本的 CRUD 操作,并且所有其他需要存储在数据库中的类都将从它继承下来。对于直接从它继承的类来说,它工作得很好,但是在将它与具有中间父级的类一起使用时,我遇到了问题。

假设我还有其他三个类,Parent、ChildA 和 ChildB,并且继承看起来像:

数据库实体
|
家长
| |
孩子A 孩子B

同时假设 DatabaseEntity<T> 有一个带有以下签名的方法:

public static T FindBy(int id)  

我遇到的问题是当我尝试类似:

ChildA Foo = ChildA.FindBy(SomeID);

我收到一个编译器错误,告诉我没有从 Parent 到 ChildA 的隐式转换。这是因为 Parent 是为 ChildA 和 ChildB 传递给 DatabaseEntity 的类型参数的类。我认为很容易解决,只需向 Parent 添加一个类型参数,从而传递适当的类型。等一下,然后我必须在任何时候使用破坏任何多态性的 Parent 显式定义子类型。不,再想一想,也许这不是一个很好的解决办法。

我认为我可以将类型参数放在类 DatabaseEntity 本身上,并让每个方法都需要一个类型参数,但是我必须这样做:

ChildA Foo = ChildA.FindBy<ChildA>(SomeID);

虽然可以编译,但它看起来不太干净,当然需要更多的输入。 Visual Studio 会询问我是否遗漏了演员表,虽然我可以直接转换我的第一个示例,但在我意外输入之前只是时间问题:

ChildB Foo = (ChildB) ChildA.FindBy(SomeID)

到目前为止,我对我想到的任何解决方案都不是特别满意,我希望这里有人能指出我错过的优雅解决方案。

【问题讨论】:

  • 您受限于哪个 .Net 版本?
  • 你需要一个支持LINQ操作的ORM,然后你可以使用OfType&lt;T&gt;来做parent到childa的转换。

标签: c# generics


【解决方案1】:

我认为将Parent 设为泛型类是可行的方法。您没有在示例中解释 T 类型的确切用途,但我想您希望它是实体的实际类型,例如您的 Parent 将继承 Entity&lt;Parent&gt;

在这种情况下你仍然可以编写多态代码——你只需要使用泛型:

static void Foo<T>(Parent<T> p) where T : Parent<T>
{
  Parent<T> entity = p.Find();
}

可以使用ChildAChildB 调用此方法。唯一棘手的方面是您实际上无法创建 Parent&lt;Parent&lt;...&gt;&gt; 的实例(因为必须将点替换为更多嵌套的 Parent&lt;...&gt; 类型),但您可以编写如下内容:

class ParentFix : Parent<ParentFix> { }

.. 那么您也可以将ParentFix 的实例传递给Foo 方法。

【讨论】:

  • 酷,我不知道你可以写这样的方法定义,仍然习惯泛型。您假设我希望 T 成为实体的实际类型是正确的。幸运的是,在这种情况下我不需要实例化 Parent 。拥有一个空的修复程序类似乎有点丑陋(无意冒犯),这是一种常见的技术还是我无意中创造了一个奇怪的场景?
【解决方案2】:

我知道这不是您要寻找的答案,但我建议使用可靠的现成 ORM,例如 Entity Framework 4。它支持开箱即用的继承,并且是基本的基本用法一个存储库。

我认为,如果您尝试自己进行此操作,您会很痛苦。

【讨论】:

  • 我实际上正在使用 NHibernate,我正在尝试设置我的 DatabaseEntity 类,因此我不必重复添加非常基本的 Find/Delete/Save 方法来为我的每个类调用 NHibernate . NHibernate 已经完成了所有繁重的工作:)
【解决方案3】:

对不起,如果我在这里没有得到更大的图景,但您可以将 DatabaseEntity&lt;T&gt; 设为单独的通用类(可能是静态类),而无需从中派生 Parent

这种安排将允许使用DatabaseEntity&lt;T&gt; 定义的所有CRUD 操作与您可能拥有的任何类。

P.S.:如果我遗漏了一些明显的东西,请不要喷我,我宁愿得到一些澄清,以便我能更好地学习。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-04
    • 1970-01-01
    • 2010-11-30
    • 2011-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多