代码之家  ›  专栏  ›  技术社区  ›  Ian Mercer

抽象泛型类,使用从该类派生的类型参数

  •  5
  • Ian Mercer  · 技术社区  · 15 年前

    您认为创建一个抽象的泛型类(将从其自身派生的类作为类型参数)是可以接受的还是不好的做法?

    这允许抽象泛型类操作派生类的实例,特别是根据需要创建派生类的新()实例的能力,并有助于避免在派生该类的具体类中重复代码。

    如果“坏”,您更喜欢处理这种情况的其他方法是什么?您将如何构造下面的代码?

    例如:

        // We pass both the wrapped class and the wrapping class as type parameters 
        // to the generic class allowing it to create instances of either as necessary.
    
        public abstract class CoolClass<T, U>
            where U : CoolClass<T, U>, new()
        {
            public T Value { get; private set; }
            protected CoolClass() { }
            public CoolClass(T value) { Value = value; }
            public static implicit operator CoolClass<T, U>(T val)
            {
                // since we know the derived type and that its new(), we can
                // new up an instance of it (which we couldn't do as an abstract class)
                return new U() { Value = val};
            }
            public static implicit operator T(CoolClass<T, U> obj)
            {
                return obj.Value;
            }
        }
    

    第二个额外的问题是:为什么这些隐式运算符中的一个有效,而另一个无效?

    例如

        public class CoolInt : CoolClass<int, CoolInt>
        {
            public CoolInt() {  }
            public CoolInt(int val) (val) { }
        }
    
                                        // Why does this not work
            CoolInt x = 5;
                                        // when this works
            CoolInt x2 = (CoolInt)5;    
                                        // and this works
            int j = x;
    
    2 回复  |  直到 15 年前
        1
  •  1
  •   Andrew Bezzub    15 年前

    这有点主观,但我不太喜欢含蓄的演员。当您使用代码时,代码常常会产生误导,有时很难找到由implisit cast引起的错误。如果你的课程是专为使用它们而设计的,那么我就不会这样使用它。

    为什么这些隐式运算符中的一个有效,而另一个无效?

    因为你定义了转换自 CoolClass<T, U> 但不是来自 CoolInt . 它们是不同的类型。如果您的Coolint实现中有这个方法,它将工作:

    public static implicit operator CoolInt(int val)
    

    关于泛型的用法 :

    如果您需要使用许多类创建复杂的继承层次结构(例如引入新的抽象级别可能很棘手),那么使用泛型会对您的体系结构造成限制。但这真的取决于你需要什么。我实际上在其中一个项目中使用了这种技术来避免代码重复。你也可以通过一个代表 Func<U> 如果您的 CoolClass 克服新的()限制:)

        2
  •  1
  •   Puppy    15 年前

    这是一个共同点(而且很好!)C++中的模式,看起来有点像:

    template<typename T> class Base {
        void foo() { T::foo(); /* Call the derived implementation*/ }
    };
    class Derived : public Base<Derived> {
        void foo() { /* do something*/ }
    };
    

    我们将它与其他方法一起用于静态多态性/继承。

    然而,在.NET中,泛型参数在运行时,也存在反射,我不完全确定它的好处在哪里。我的意思是,拥有派生类型是有用的,但是你必须问自己——对什么有用,它与直接继承有什么不同?