私はいくつかのコードを見ていますが、次のクラス定義で特定の制約が何を意味するのか理解できません:
internal abstract class Entity<T> : Entity
where T : Entity<T>
{ ... }
これが parameter type について何を意味するのかわかりませんT
。
私はいくつかのコードを見ていますが、次のクラス定義で特定の制約が何を意味するのか理解できません:
internal abstract class Entity<T> : Entity
where T : Entity<T>
{ ... }
これが parameter type について何を意味するのかわかりませんT
。
これは、" Curiously Recurring Template Pattern "に似ています (ただし、同じではありません)。
派生クラスのメソッドのパラメーターの型を、派生クラス自体と同じ型に制約するために (とりわけ) 使用できます。
このテーマに関する Eric Lippert の興味深いブログ投稿を次に示します。
Entity<T>
これの主な用途は、派生クラスと同じ型のパラメーターを受け入れる何らかのメソッドを実装することを派生クラスに強制することです。
次のコード サンプルでは、 type のパラメーターを受け入れる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>
か、その型から派生している必要があると書かれています
逆説的なように思えますが、有効であり、時には有用な場合もあります。
これは、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
}
もちろん、これは制約なしで機能しますが、機能的な観点から、または意図を示すために意味がある場合があり、コードの他の部分で必要になる場合があります。
that T
must be or inherit fromと書いてありますがEntity<T>
、これはT
あなたが制限しているものです。それは抽象的であるため、明らかにそれT
はできませんEntity<T>
。したがって、それを継承するものでなければなりません。