在 C# 4.0 中,是不是可以从泛型类型参数派生类?

Posted

技术标签:

【中文标题】在 C# 4.0 中,是不是可以从泛型类型参数派生类?【英文标题】:In C# 4.0, is it possible to derive a class from a generic type parameter?在 C# 4.0 中,是否可以从泛型类型参数派生类? 【发布时间】:2011-08-18 22:20:39 【问题描述】:

我一直在尝试这个,但我似乎无法弄清楚这一点。我想做这个……

public abstract class SingletonType<TSingleton, TBaseClass> : TBaseClass
    where TSingleton : TBaseClass, new()
    where TBaseClass : class

    static TSingleton _singleton;
    public static TSingleton Singleton
        => _singleton ?? (_singleton = new TSingleton());

计划是像这样使用它,将单例模式“包装”在基类周围...

public class SingletonFoo : SingletonType<SingletonFoo, Foo> 

但是,我不断收到这个

不能从 'TBaseClass' 派生,因为它是一个类型参数

嗯...我认为类型正是您所做的派生的!

那么我错过了什么?

注意:这当然是一个简单的例子,因为它没有添加任何有用的东西,但假设 SingletonType 有很多与问题无关的其他逻辑,因此它被省略了专注于手头的问题。

【问题讨论】:

你说,“嗯......我认为类型正是你所衍生的!” — 是的,但请再次阅读消息。它说“类型参数”,不是“类型”。这是不同的。 然而,您可以在使用类型的泛型中的任何地方使用该“类型参数”(例如“公共静态 T”),那么如何以我想要的方式使用它与使用它作为返回不同类型? (到目前为止,@Tejs 似乎最有洞察力。) 可能值得注意的是,与继承相反,组合在这里更为理想。 @Mohamed Nuur,想详细说明一下吗? (......或者任何人都可以?)不知道你的意思。 Why cannot C# generics derive from one of the generic type parameters like they can in C++ templates?的可能重复 【参考方案1】:

C# 中的泛型类型不是 C++ 模板;请记住,泛型类型必须适用于所有可能的类型参数。模板只需要适用于您实际制作的结构。

这个问题是重复的;看我的回答

Why cannot C# generics derive from one of the generic type parameters like they can in C++ templates?

有关此的更多想法。基本上,简短的回答是,可观的成本并没有超过该功能的小好处。如果您不喜欢该答案,请参阅我的第二个答案:

Why cannot C# generics derive from one of the generic type parameters like they can in C++ templates?

如果您也不喜欢这个答案,请查看后续问题:

What are the good reasons to wish that .NET generics could inherit one of the generic parameter types?

【讨论】:

【参考方案2】:

不,这是不可能的。例如,采用声明为sealed 的类型。您不能从该类继承,并且没有限制非密封类型的限制,因此尝试通过泛型参数从它继承是不可能的。

【讨论】:

好吧,这并不能真正解释原因——编译器可能只是不允许使用MyType&lt;X&gt;,其中X 是密封类型,而不是完全禁止声明MyType&lt;T&gt; : T。但当然答案仍然是“不可能”:) 好吧,为什么泛型参数必须对所有允许的类型都有效;例如,new() 约束允许您编写T sample = new T(),因为否则您的通用参数可能是int,这不是有效代码。如果没有nosealed 约束,继承带有密封的东西将违反 C# 规范。因为不是所有情况都对一个类型有效,并且不存在约束,所以它是无效的。错误消息是编译器不允许这种情况发生 =D 不,肤浅的原因是规范说基本类型不能是类型参数,句号。您试图提供的深层原因是规范以这种方式编写的原因。您对此提供了一个非解释。 (顺便说一句,int 确实有一个默认构造函数,因此满足 new() 约束,所有值类型也是如此。)跨度> @MarqueIV:你的评论毫无意义。没有object 约束。也许你的意思是class,但是你的评论是错误的:你可以有一个new()没有class约束。【参考方案3】:

每个类型都有 1 个真实的、离散的父类,即使涉及泛型也是如此。即使在处理开放的泛型类型(例如,typeof(List&lt;&gt;))时,您仍然可以找到父类。

如果你想要的东西被允许,这将是不正确的,typeof(SingletonType&lt;,&gt; 将没有父类型,这是不允许的。

【讨论】:

【参考方案4】:

不,这是不可能的,因为假设你有这个类:

class bar 
  int example = 0;

现在这是我们的类型参数类:

class foo<T> : T 
  int example = 5;

如果我们创建了foo&lt;bar&gt; 类型的变量,那么example 就会混淆。

【讨论】:

怎么会混在一起呢? ‘Bar’ 有一个类型参数,而不是基类。它们完全不相关,而且范围不同。 @MarqueIV 不,因为Tbarfoo&lt;bar&gt; 的一种。由于foo 类继承自T 类(bar),因此example 可以是05 很抱歉,这是不正确的。它们的范围完全不同。您可以从泛型实例访问一个示例,而从泛型中通过 T 定义的任何实例变量访问另一个示例。它们不是一回事。 您似乎不明白继承在 C# 中是如何工作的。 examplebar 中是私有的,因此来自bar 的派生类可以毫无问题地声明自己的example。即使example 不是私有的,那么foo&lt;T&gt;example 也会被视为new 哦,我明白了,打扰了

以上是关于在 C# 4.0 中,是不是可以从泛型类型参数派生类?的主要内容,如果未能解决你的问题,请参考以下文章

Scala - 从泛型类型获取类对象

为啥 C# (4.0) 不允许泛型类类型中的协变和逆变?

从泛型类型快速实例化

从泛型问题推断

如何在 Spring Boot 中从泛型参数(与任何类无关)中获取值

如何从泛型函数中记录参数[重复]