我正在查看一些代码,但我不明白特定约束在以下类定义中的含义:
internal abstract class Entity<T> : Entity
where T : Entity<T>
{ ... }
我不明白这对参数类型意味着什么T
。
我正在查看一些代码,但我不明白特定约束在以下类定义中的含义:
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>
。
它是一种经常使用的自引用泛型,使得基类可以在方法和其他区域中包含派生类类型(via )。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
}
这当然可以在没有约束的情况下工作,但从功能的角度来看它可能仍然有意义或显示意图,并且在代码的其他部分可能需要它
它说 that T
must be or inherit from Entity<T>
,这就是T
你要限制的东西。显然T
不能是,Entity<T>
因为那是抽象的,所以它必须是继承自它的东西。