abstract class Animal { }
class Mammal : Animal { }
class Dog : Mammal { }
class Reptile : Animal { }
class AnimalWrapper<T> where T : Animal
{
public ISet<AnimalWrapper<T>> Children { get; set; }
}
class Program
{
public static void Main(string[] args)
{
var foo = new AnimalWrapper<Mammal>();
foo.Children = new HashSet<AnimalWrapper<Mammal>>();
var child = new AnimalWrapper<Dog>();
foo.Children.Add(child);
}
}
これは明らかにコンパイルされません。foo.Children.Add(child);
上記のコードが私がやりたいことを示す最も明確な方法であるかどうかわからないので、平易な英語で説明しようとします:
ISet
Children オブジェクトが同じジェネリック型のクラスを持つ機能が必要です。したがって、私もそれを持っていた場合var child = new AnimalWrapper<Reptile>();
、コンパイル時に、is ではなく、 から継承しないfoo.Children.Add(child);
ため、実行に失敗します。しかし、明らかに、派生したとしても、上記のように機能しません。Reptile
Mammal
最終的には、そのセットにISet<AnimalWrapper<Animal>> baz = new HashSet<AnimalWrapper<Animal>>();
a を追加して、同じセットに追加できるといいですね。そして、それらの子は、前述のように、ある意味で独自のタイプであるプロパティを持ちます。new AnimalWrapper<Mammal>()
new AnimalWrapper<Reptile>()
Children
ISet<AnimalWrapper<T>>
方法はありますか、それとも C# に期待しすぎているのでしょうか? 一体私は自分自身を混乱させています。:)
編集:わかりましたので、 なしでこれをほぼ理解しましAnimalWrapper
たが、基本IAnimal
インターフェースを使用すると、ほとんど機能します:
interface IAnimal { }
abstract class Animal<T> : IAnimal where T : Animal<T>
{
public ISet<T> Children { get; set; }
}
class Mammal : Animal<Mammal> { }
class Dog : Mammal { }
class Reptile : Animal<Reptile> { }
class Frog : Reptile { }
class Program
{
public static void Main(string[] args)
{
var animals = new HashSet<IAnimal>(); // any animal can be in this
var mammal = new Mammal();
animals.Add(mammal);
mammal.Children = new HashSet<Mammal>();
var dog = new Dog();
mammal.Children.Add(dog); // ok! a dog is a mammal
dog.Children = new HashSet<Dog>(); // in theory, OK, but compile time error
// because Dog : Mammal, and Mammal defines Animal<Mammal>, therefore Dog's
// Children is actually ISet<Mammal>, rather than ISet<Dog> (which is what
// I want, recursively apply the T in Animal.
Mammal mammal2 = new Mammal();
dog.Children.Add(mammal2); // should be verboten, but is allowed for the
// same reason above.
}
}