Base class constraint on generic class specifying the class itself

给你一囗甜甜゛ 提交于 2020-07-15 11:13:04

问题


Yesterday, I was explaining C#'s generic constraints to my friends. When demonstrating the where T : CLASSNAME constraint, I whipped up something like this:

public class UnusableClass<T> where T : UnusableClass<T>
{
    public static int method(T input){
        return 0;
    }
}

And was really surprised to see it compile. After a bit of thinking, however, I figured it was perfectly legal from the point of view of the compiler - UnusableClass<T> is as much of a class as any other that can be used in this constraint.

However, that leaves a couple of questions: how can this class ever be used? Is it possible to

  1. Instantiate it?
  2. Inherit from it?
  3. Call its static method int method?

And, if yes, how?

If any of these is possible, what would the type of T be?


回答1:


Well.

public class Implementation : UnusableClass<Implementation>
{
}

is perfectly valid, and as such makes

var unusable = new UnusableClass<Implementation>();

and

UnusableClass<Implementation>.method(new Implementation());

valid.

So, yes, it can be instantiated by supplying an inheriting type as the type parameter, and similarly with the call to the static method. It's for instance useful for tree-like structures where you want to generically specify the type of children the node has, while it being the same type itself.




回答2:


This approach is widely used in Trees and other Graph-like structures. Here you say to compiler, that T has API of UnusableClass. That said, you can implement TreeNode as follows:

public class TreeNode<T>
    where T:TreeNode<T>
{
    public T This { get { return this as T;} }

    public T Parent { get; set; }

    public List<T> Childrens { get; set; }

    public virtual void AddChild(T child)
    {
        Childrens.Add(child);
        child.Parent = This;
    }

    public virtual void SetParent(T parent)
    {
        parent.Childrens.Add(This);
        Parent = parent;
    }
}

And then use it like this:

public class BinaryTree:TreeNode<BinaryTree>
{
}



回答3:


If any of these is possible, what would the type of T be?

They are all possible, and you are the one who is gonna determine what is the type of T.For example let's assume there is a type that inherits from UnusableClass<T>

class Foo : UnusableClass<Foo> { }

Now you can instantiate UnusableClass<Foo> because Foo satisfies the constraint:

UnusableClass<Foo> f = new UnusableClass<Foo>();

Then the type of T become Foo and if you try to call method you need to pass an instance of Foo.



来源:https://stackoverflow.com/questions/29228636/base-class-constraint-on-generic-class-specifying-the-class-itself

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!