我在看一些代碼,我不明白什麼是特定的約束在下面的類定義是指:這個參數類型約束是什麼意思?
internal abstract class Entity<T> : Entity
where T : Entity<T>
{ ... }
我不明白,這意味着有關參數類型T
。
我在看一些代碼,我不明白什麼是特定的約束在下面的類定義是指:這個參數類型約束是什麼意思?
internal abstract class Entity<T> : Entity
where T : Entity<T>
{ ... }
我不明白,這意味着有關參數類型T
。
這與「Curiously Recurring Template Pattern」類似(但它不相同)。
它可以用來(除其他外)幫助將派生類中的方法的參數類型約束爲與派生類本身相同的類型。
Here's an interesting blog post from Eric Lippert on this subject。
此主要用於強制從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
繼承。顯然T
不能是Entity<T>
因爲這是抽象的,所以它必須是從它繼承的東西。
它說,T必須Entity<T>
類型或從該類型
派生雖然它似乎是自相矛盾它是有效的,有時是太有用,雖然情況是罕見的,往往可以在不同的處理更容易undertand方法。
它經常refered在C++行話爲Curiously recurring template pattern
在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
}
這當然與出約束的工作,但它仍然可能從功能角度看是有意義還是表現出打算,並可能在其他部分需要代碼
爲什麼是DW?這個答案中沒有任何不正確的,它回答了這個問題 – 2013-04-22 08:39:20
雖然我評論過,我會堅持我的槳,因爲我也想說明基礎類型從中得到什麼。
只需: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 ;-)
我很抱歉,但你不混淆C++模板與C#泛型? – 2013-04-22 08:38:37
C#的原理不一樣嗎?重要的是這種類型受到這種限制。 – 2013-04-22 08:40:12
我同意,這個答案是不正確的。在CRTP中,基類也是通用的,這裏不是這種情況。如果你在這裏說'Base''與'Entity '相同,你也是不正確的,因爲在C#中你不能以這種方式訪問派生類的成員。 –
2013-04-22 08:40:16