抽象泛型类采用本身派生自该类的类型参数

发布于 2024-09-11 11:55:33 字数 1505 浏览 3 评论 0原文

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

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

如果“不好”,您更喜欢什么替代方案来处理这种情况?您将如何构建下面的代码?

例如:-

    // 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;

Do you consider it an acceptable or a bad practice to create an abstract generic class that takes as a type parameter a class that derives from itself?

This allows the abstract generic class to manipulate instances of the derived class and in particular the ability to create new() instances of the derived class as necessary and can help avoid repeat code in the concrete classes that derive from it.

If 'bad' what alternative do you prefer to handle such situations and how would you structure the code below?

For example:-

    // 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;
        }
    }

And a second bonus question: why does ONE of these implicit operators work and the other one not?

e.g.

    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;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我一向站在原地 2024-09-18 11:55:33

这有点主观,但我不太喜欢隐式转换。当您使用它们时,代码常常会产生误导,有时如果是由隐式强制转换引起的错误,则很难找到错误。如果您的课程只是为了使用它们而设计的,那么我不会以这种方式使用它。

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

因为您定义了来自 CoolClass 的转换,而不是来自 CoolInt 的转换。它们是不同的类型。如果您在 CoolInt 实现中使用此方法,它将起作用:

public static implicit operator CoolInt(int val)

关于泛型的使用

如果您需要使用许多类创建复杂的继承层次结构(例如引入新的类),则泛型的这种使用会对您的体系结构产生限制。抽象级别可能很棘手)。但这实际上取决于您的需要。我实际上在一个项目中使用了这种技术来避免代码重复。如果您的 CoolClass 克服 new() 限制,您也可以将委托 Func 传递给构造函数:)

It is a bit subjective but I'm not a big fan of the implicit casts. Code often becomes misleading when you use them and sometimes it is hard to find a bug if it is cause by implisit casts. If your class is designed only for use of them than I wouldn't use it in this way.

why does ONE of these implicit operators work and the other one not?

Because you defined convertion from CoolClass<T, U>, but not from the CoolInt. They are different types. It would work if you had this method in your CoolInt implementation:

public static implicit operator CoolInt(int val)

About usage of generics:

Such usage of generics creates limitations to your architecture if you would need to create complex inheritance hierarchies with many classes (e.g. introducing new level of abstraction could be tricky). But this really depends on what you need. I actually used such tecnique in one of the projects to avoid code duplication. Also you could pass a delegate Func<U> to the constructor if your CoolClass to overcome new() restriction :)

2024-09-18 11:55:33

这是 C++ 中的一种常见(而且很好!)模式,看起来有点像这样:

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

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

然而,在 .NET 中,通用参数在运行时并且还存在反射,我不完全确定好处在哪里。我的意思是,拥有派生类型很有用,但您必须问自己 - 有什么用,以及它与直接继承有何不同?

It's a common (and good!) pattern in C++, that looks a little like this:

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

We use it for static polymorphism/inheritance, along with others.

However, in .NET where generic parameters are at runtime and there is also reflection, I'm not entirely sure where the benefit would be. I mean, having the derived type is useful, but you have to ask yourself- useful for what, and how does it differ from straight inheritance?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文