如何在C#中编写一个好的反复出现的模板模式(CRTP)

时间:2012-06-07 21:09:02

标签: c# crtp

前段时间我想创建自己的数据映射器,它比普通的ORM简单得多。这样做我发现需要访问我的基类中继承类的类型信息。我的第一个想法是反思,但它太慢了(如果你使用反射,请查看Fasterflect,因为它“几乎”消除了反射的性能问题。)

所以我转向了一个解决方案,我后来发现它有自己的名字:奇怪的重复模板模式。这主要解决了我的问题,但学习如何正确实现这种模式有点挑战。我必须解决的两个主要问题是:

1)如何让我的消费代码能够使用我的通用对象,而无需知道创建对象的通用参数?

2)如何在C#中继承静态字段?

具有挑战性的部分实际上是在弄清问题。一旦我意识到我需要做什么,解决这些问题就很容易了。如果你发现自己需要CRTP,你可能会发现自己需要回答这些问题......它们似乎是相辅相成的。

1 个答案:

答案 0 :(得分:11)

在不知道通用参数类型的情况下使用泛型

当使用CRTP时,最好有一个非泛型基类(如果可能的话抽象,但这并不太重要),你的'基础'泛型类继承自。然后,您可以在非泛型基类上创建抽象(或虚拟)函数,并允许使用代码来处理对象,而无需知道通用参数。例如:

abstract class NonGenBase
{
    public abstract void Foo();
}

class GenBase<T>: NonGenBase
{
    public override void Foo()
    {
        // Do something
    }
}

现在消耗不知道T应该是什么的代码仍然可以通过将它们视为基类的实例来调用对象上的Foo()过程。

如何解决静态字段继承问题

使用CRTP解决问题时,在继承类中提供对静态字段的访问通常是有益的。问题是C#不允许继承类访问那些静态字段,除非通过类型名称...这通常似乎在这种情况下失败了。你可能无法想到我正在谈论的一个明确的例子,解释一个超出了这个答案的范围,但解决方案很简单,所以只需将它放在你的知识库中,当你发现需要它时你会很高兴它在那里:)

class GenBase<T>: NonGenBase
{
    static object _someResource;

    protected object SomeResource { get { return _someResource; } }
}

这是'模拟'静态字段的继承。但请记住,泛型类上的静态字段不是跨所有通用实现的。每个通用实现都有自己的静态字段实例。如果您想要一个可用于所有实现的静态字段,那么您只需将其添加到非泛型基类中。