2013-10-08 42 views
16

我第一次看到一位同事在执行对象池时做这件事。他将这个类作为参数传递给泛型基类。这个基类放出了合并代码。是否让类将自身作为参数传递给泛型基类邪恶?

奇怪的是,基类会知道它的孩子。这在每个正常情况下被认为是不好的做法。但在这种情况下,父母只是避免编写重复代码的技术解决方案。基类不会被任何其他代码引用。

这种结构的一个缺点是它“烧伤基础类”。您不能在层次结构中引入泛型基类。这个问题可能超出了这个话题。

下面是一个可以想到例如:

public abstract class Singleton<T> where T : class 
{ 
    public static T Instance { get; private set; } 

    public Singleton() 
    { 
     if (Instance != null) 
      throw new Exception("Singleton instance already created."); 
     Instance = (T) (object) this; 
    } 
} 

public class MyClass : Singleton<MyClass> 
{ 
} 

改进代码:

public abstract class Singleton<T> where T : Singleton<T> 
{ 
    public static T Instance { get; private set; } 

    public Singleton() 
    { 
     if (Instance != null) 
      throw new Exception("Singleton instance already created."); 
     Instance = (T) this; 
    } 
} 

public class MyClass : Singleton<MyClass> 
{ 
} 

回答

14

否;这是一个众所周知的模式,称为CRTP
它在C++中作为虚拟方法的替代方法特别有用。

您可以在.Net框架中看到它IComparable<T>IEquatable<T>

增强坚固性,您应该添加where T : Singleton<T>

+0

你最后一句话让我心动。 class SingleTon where T:Singleton ?这不需要你无限递归(每个T必须是Singleton ,其中T将再次是单例等) – Kristof

+0

增加了SLaks代码改进。第一行确实让你头晕目眩。 –

+0

@Kristof参见上面的例子:'public MyClass:Singleton '。这种类型,“MyClass”IS-A'Singleton '所以它的工作原理。尽管如此,它仍然有点脑筋急转弯。 –

3

SLaks是正确的 - 这是一个有用的模式,通常当你想在其中是强类型的,以你的派生类的基类提供代码。

您通常还会为泛型参数添加一个类型约束,以指示泛型类型必须从抽象类型继承。添加此约束的语法看起来是递归的,但不要惊慌 - 它不会被递归计算,而只是确保唯一有效的泛型类型是派生类。

例如,假设您经营茶和咖啡混合业务。把咖啡和咖啡,茶和茶混合在一起是有道理的,但是你要确保你不能混合咖啡和茶。然而,因为它们都是饮料,所以你想用同样的方式对它们进行建模。

public abstract class Beverage<T> where T : Beverage<T> 
{ 
    public abstract T Blend(T drink1, T drink2); 
} 

public class Tea : Beverage<Tea> 
{ 
    public override Tea Blend(Tea drink1, Tea drink2) 
    { 
     // Blend tea here. 
    } 
} 
public class Coffee : Beverage<Coffee> 
{ 
    public override Coffee Blend(Coffee drink1, Coffee drink2) 
    { 
     // Blend coffee here. Although coffee is nasty, so 
     // why you'd want to is beyond me. 
    } 
} 

阅读关于CRTP时,值得记住的是C++模板只是表面上类似于C#泛型。关键的区别在于模板实际上是编译时工作的代码生成工具,而运行时支持C#泛型。

此外,编写这样的代码会降低可读性。因此,虽然肯定会有这种情况是正确的,但您应该考虑一下您尝试解决的问题,并确定是否有更直接的方法。

+0

MyClass.Instance会编译。 –

+0

已编辑适当。 –

+2

当然,'公共课咖啡:饮料'是一个法律声明。这很容易搞砸了。 – Brian

相关问题