4

在“C# 6.0 in a Nutshell”中有一个裸类型约束用法的示例:

class Stack<T>
{
  Stack<U> FilteredStack<U>() where U : T {...}
}

老实说,我不明白为什么我应该在这里使用这个约束。如果我将其删除并将 U 更改为 T,结果将是相同的。那么有什么意义呢?

谢谢你。

4

3 回答 3

9

关键是它U可以是任何类型的子类T,而Stack你得到的是类型的堆栈,而不是T. 因此,添加到其中的项目必须是 type ,并且如果它们不为空U,则可以保证从其中返回的项目是。U所有熟悉的编译时类型检查的喜怒哀乐。

中的项目Stack<T>可以是 type T,也可以是 的任何子类T。该方法的名称表明它返回的堆栈仅包含父堆栈中实际上属于某个特定子类的项。一旦您保证新堆栈中的所有项目都是更专业的类型,那么如果这也是新堆栈的类型,那么它会更加有用。

这是一个非常人为的示例(显然,这个“堆栈”类实际上并没有做堆栈所做的任何事情,但对于我们的示例来说它不需要):

public class A
{
    public A(String s)
    {
        SA = s;
    }
    public String SA { get; set; }
}

public class B : A
{
    public B(String s, string s1)
    {
        SA = s;
        SB = s1;
    }
    public String SB { get; set; }
}

class Stack<T>
{
    Stack<U> FilteredStack<U>() where U : T
    {
        return new Stack<U>(Items.OfType<U>());
    }

    public IEnumerable<T> Items { get { return _items; } }

    public static void Test()
    {
        var s1 = new Stack<A>(new[] { new A("A1"), new B("B1", "Some other value") });
        var s2 = s1.FilteredStack<B>();

        //  s2 is a strongly typed stack of type B
        Console.WriteLine(s2.Items.First().SB);
    }


    private List<T> _items = new List<T>();
    public Stack(IEnumerable<T> items) {
        _items = new List<T>(items);
    }
}
于 2017-08-30T18:33:52.420 回答
4

如果你有一个Stack<Animal>你可以FilteredStack<Dog>用来得到一个Stack<Dog>。关键是您要确保U传递给FilteredStack的类型是派生自T但不一定T

于 2017-08-30T18:36:10.053 回答
0

泛型约束用于限制泛型类型、函数等的访问。

其中 U : T 表示只有从 U 继承的那些类才能访问函数 FilteredStack()。那些不是从 U 继承的类的对象不应该能够访问 FilteredStack() 并且它会给出一个编译错误。这是类型安全的全部目的

于 2017-08-30T18:36:32.457 回答