这个参数类型约束是什么意思
本文关键字:是什么 意思 约束 类型 参数 | 更新日期: 2023-09-27 18:10:13
我正在看一些代码,我不明白在下面的类定义中一个特定的约束是什么意思:
internal abstract class Entity<T> : Entity
where T : Entity<T>
{ ... }
我不明白这对参数类型T
意味着什么。
这类似于"奇怪的循环模板模式"(但并不相同)。
它可以用来帮助约束派生类中方法的参数类型,使其与派生类本身的类型相同。
这是Eric Lippert关于这个主题的一篇有趣的博客文章。
它的主要用途是强制从Entity<T>
派生的类实现一些方法,该方法接受与派生类相同类型的参数。
在下面的代码示例中,我们在Entity<T>
类中声明了一个方法DoSomethingWithTheSameTypeAsMe()
,它接受一个类型为T
的参数。
由于泛型约束,这将强制从Entity<T>
派生的任何类实现DoSomethingWithTheSameTypeAsMe()
的一个版本,该版本接受派生类类型的参数。
这是有限的使用,它是非常令人困惑的阅读,所以我同意Eric Lippert说,你应该避免这样的代码!
using System;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main()
{
var test1 = new Derived1();
var test2 = new Derived2();
test1.DoSomethingWithTheSameTypeAsMe(test1);
test2.DoSomethingWithTheSameTypeAsMe(test2);
}
}
public class Entity
{
public string Hello()
{
return "Hello, World.";
}
}
public abstract class Entity<T>: Entity where T: Entity<T>
{
public abstract void DoSomethingWithTheSameTypeAsMe(T item);
}
public sealed class Derived1: Entity<Derived1>
{
// You are forced to implement DoSomethingWithTheSameTypeAsMe() with a param type "Derived1".
// (i.e. the parameter is the same type as 'this')
public override void DoSomethingWithTheSameTypeAsMe(Derived1 item)
{
Console.WriteLine("Doing something with a Derived1 item: " + item.Hello());
}
}
public sealed class Derived2: Entity<Derived2>
{
public override void DoSomethingWithTheSameTypeAsMe(Derived2 item)
{
Console.WriteLine("Doing something with a Derived2 item: " + item.Hello());
}
}
}
尽管我已经注释过了,但我还是要把我的桨插进去,因为我还想注意基本类型从中得到什么
简单:T
必须继承Entity<T>
。
这是一种经常使用的自引用泛型,这样基类可以在方法和其他领域包含派生类类型(通过T
)。它只是避免了您必须在派生类型中强制转换内容或使用基引用。它可能非常有用,尽管我很少在代码中看到它。
object
是已知最低的类型。从派生类型的角度来看,它的好处在于它为推入基类的代码提供了整洁性。
在您的示例中,它将看到Entity<T>
和Entity
成员。这就是约束的原因。
标准用法是这样的:
public class Customer : Entity<Customer>
{
}
public abstract class Entity<T>
where T : Entity<T>
{
public T Clone(T entityToClone)
{
return default(T); // Clone code here, returns derived type.
}
}
// Grants you...
Customer clonedCustomer = currentCustomer.Clone();
// Instead of...
Customer clonedCustomer = (Customer)currentCustomer.Clone();
// Ignore ethical constraints on cloning customers and definitely do not tell your sales team that you can ;-)
它说T必须是类型Entity<T>
或从该类型派生
虽然看起来有点矛盾,但它是有效的,有时也是有用的,尽管这种情况很少,而且通常可以用不同的更容易理解的方式处理。
在c++术语中,它通常被称为奇怪的反复出现的模板模式
在c#中的功能比在c++中使用模式时更受限制,该模式的具体类通常看起来像这样
class MyClass<ItemType> : Entity<MyClass<ItemType>> {
//...
}
或
class MyClass : Entity<MyClass> {
//...
}
当处理类型上的属性时,这可能是有用的一个例子。
假设您正在运行时创建一个小部件列表。该列表包括来自Entity<T>
的所有类型,您可以根据来自属性的元数据填充信息。在Entity<T>
中,你可以一劳永逸地处理这个
void RegisterWidget(){
var attributes = typeof(T).GetAttributes();
//do what ever you need to
}
这当然可以在没有约束的情况下工作,但从功能的角度来看,它仍然是有意义的,或者显示意图,并且可能需要在代码的其他部分
它说T
必须是或继承自Entity<T>
,这就是您所限制的T
。显然,T
不能是Entity<T>
,因为那是抽象的,所以它必须是从它继承的东西。