- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
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
中属于相同的通用类型。因此,如果我也有 var child = new AnimalWrapper<Reptile>();
它会在编译时失败 foo.Children.Add(child);
因为Reptile
不是也不继承自 Mammal
.但是,很显然,即使是派生出来的,如上图,也是不行的。
最终,能够说 ISet<AnimalWrapper<Animal>> baz = new HashSet<AnimalWrapper<Animal>>();
会很好然后添加 new AnimalWrapper<Mammal>()
到那个集合,和new AnimalWrapper<Reptile>()
到同一套。他们的 child 将拥有属性(property)Children
那是一个ISet<AnimalWrapper<T>>
在某种程度上,它是自己的类型,如上所述。
有什么办法还是我对 C# 的期望太高了?哎呀,我把自己搞糊涂了。 :)
编辑: 好的,所以我几乎想通了,没有 AnimalWrapper
, 但以 IAnimal
为基数接口(interface),它几乎可以工作:
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.
}
}
最佳答案
主要问题是在协方差向上转换(以及与 ISet 的逆变)中有点过于简单化
这样试试……
abstract class Animal { }
class Mammal : Animal { }
class Dog : Mammal { }
class Reptile : Animal { }
interface INode<out T> where T : Animal
{
T MySelf { get; }
IEnumerable<INode<T>> Children { get; }
}
class Node<T> : INode<T>
where T : Animal
{
public Node() { this.Children = new HashSet<INode<T>>(); }
public T MySelf { get; set; }
public ISet<INode<T>> Children { get; set; }
IEnumerable<INode<T>> INode<T>.Children { get { return this.Children; } }
}
class Program
{
static void Main(string[] args)
{
// this is a 'typical' setup - to test compiler 'denial' for the Reptile type...
Node<Mammal> tree = new Node<Mammal>();
tree.MySelf = new Mammal();
var node1 = new Node<Mammal>();
tree.Children.Add(node1);
var node2 = new Node<Dog>();
tree.Children.Add(node2);
var node3 = new Node<Reptile>();
// tree.Children.Add(node3); // this fails to compile
// ...and similar just more 'open' - if you 'collect' animals, all are welcome
Node<Animal> animals = new Node<Animal>();
animals.MySelf = new Mammal();
INode<Mammal> mamals = new Node<Mammal>();
animals.Children.Add(mamals);
var dogs = new Node<Dog>();
animals.Children.Add(dogs);
INode<Animal> reptiles = new Node<Reptile>();
animals.Children.Add(reptiles);
}
}
(查看评论)
这并不意味着它可以在您的现实生活中使用 - 因为这需要一些“设计重构”以使其适用于更复杂的结构(如果可能)。
...只是快点,如果需要我稍后再解释
关于c# - 如何制作仅包含一组自身类型或子类型的泛型类作为子类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15590540/
我是一名优秀的程序员,十分优秀!