C# 为什么TRest在元组中<;T1。。。TRest>;不受约束?

C# 为什么TRest在元组中<;T1。。。TRest>;不受约束?,c#,.net,constraints,tuples,C#,.net,Constraints,Tuples,在一个元组中,如果有7个以上的项,则可以提供另一个元组中的第8个项,并最多定义7个项,然后将另一个元组定义为第8个项。但是,在编译时对第8项没有约束。例如,这是编译器的法定代码: var tuple = new Tuple<int, int, int, int, int, int, int, double> (1, 1, 1, 1, 1, 1, 1, 1d); var tuple=新的tuple (1,1,1,1,1,1,1,1,1,1d); 尽管

在一个元组中,如果有7个以上的项,则可以提供另一个元组中的第8个项,并最多定义7个项,然后将另一个元组定义为第8个项。但是,在编译时对第8项没有约束。例如,这是编译器的法定代码:

var tuple = new Tuple<int, int, int, int, int, int, int, double>
                (1, 1, 1, 1, 1, 1, 1, 1d);
var tuple=新的tuple
(1,1,1,1,1,1,1,1,1,1d);
尽管intellisense文档说TRest必须是一个元组。编写或构建代码时不会出现任何错误,直到运行时它才会以ArgumentException的形式出现

您可以在几分钟内大致实现一个元组,并完成一个元组约束项。我只是想知道为什么当前的实现没有考虑它?这是否可能是一个前向兼容性问题,他们可以用假设的C#5添加更多元素

粗略实施的简短版本

interface IMyTuple { }

class MyTuple<T1> : IMyTuple
{
    public T1 Item1 { get; private set; }
    public MyTuple(T1 item1) { Item1 = item1; }
}

class MyTuple<T1, T2> : MyTuple<T1>
{
    public T2 Item2 { get; private set; }
    public MyTuple(T1 item1, T2 item2) : base(item1) { Item2 = item2; }
}

class MyTuple<T1, T2, TRest> : MyTuple<T1, T2> where TRest : IMyTuple
{
    public TRest Rest { get; private set; }
    public MyTuple(T1 item1, T2 item2, TRest rest)
        : base(item1, item2)
    {
        Rest = rest;
    }
}
接口IMyTuple{}
类MyTuple:IMyTuple
{
公共T1项1{get;私有集;}
公共MyTuple(T1 item1){item1=item1;}
}
类MyTuple:MyTuple
{
公共T2项2{get;私有集;}
公共MyTuple(T1项1,T2项2):基(项1){item2=item2;}
}
类MyTuple:MyTuple,其中TRest:IMyTuple
{
公共树Rest{get;私有集;}
公共MyTuple(T1项1、T2项2、TRest rest)
:基本(项目1、项目2)
{
休息=休息;
}
}

var mytuple=新的mytuple
(1,1,新MyTuple(1));//合法的
var mytuple2=新的MyTuple(1,2,3);//编译时非法

假设的
ITuple
约束不会真正将其约束为元组[1],是吗?只是一个实现
ITuple
的类


[1] -我将“tuple”定义为BCL提供的
tuple
类之一。

它是类型系统的补充<代码>ITuple是一个内部接口。如果它是一个通用约束,那么它需要是公共的,这样每个人都可以实现自己的
ITuple
,而这与元组无关。将其限制为内部可以让BCL团队保证它实际上是某种元组,但会导致
TRest
的编译时安全性比它可能的要低一些。

真的吗?如何实现这一点,从而将最后一个元素约束为任意大小的
元组
,而不定义在各种通用
元组
大小中常见的附加基类或接口?我不明白你认为他们怎么能在C#中做到这一点。@mquander,Tuple实现了ITuple。您可以定义自己的Tuple(MyTuple)类型,将最后一项约束到接口(IMyTuple),然后进行编译时检查。谢谢你的更正。我注意到,
ITuple
是内部的;也许他们想把它保持在内部——如果它在这里是一个约束,那么它就必须是公共的。可能需要添加一个“f#”标记,因为f#team是System.Tuple的推动力。也许F#与这个设计决策有关。这是一个有趣的观点。没错,任何旧类型都可以实现接口(无论需要什么),并满足约束的要求。但是我想这也引出了一个问题,为什么要在运行时限制类型,你可以把一个元组放到任何一个现有的槽中,只要说“我们正在创建一个8槽(max)泛型类,你认为合适的话就使用它。”这是唯一真正将它限制为元组的方法(运行时检查
内部
接口,因此我们无法实现它)。最后一个插槽实际上必须是一个元组,因为它影响
大小
GetHashCode
ToString
等的实现。它的处理方式与其他插槽完全不同。
var mytuple = new MyTuple<int, int, MyTuple<int>>
                 (1, 1, new MyTuple<int>(1)); // legal
var mytuple2 = new MyTuple<int, int, int>(1, 2, 3); // illegal at compile time