2010-06-08 4 views
5

Wenn Sie in einem Tupel mehr als sieben Elemente haben, können Sie ein achtes Element angeben, das ein weiteres Tupel ist, und bis zu sieben Elemente definieren. Anschließend können Sie ein weiteres Tupel als achtes Element definieren. Es gibt jedoch keine Einschränkung für das 8. Element zum Zeitpunkt der Kompilierung. Zum Beispiel ist dieses Recht Code für den Compiler:Warum ist TRest in Tupel <T1... TRest> nicht eingeschränkt?

var tuple = new Tuple<int, int, int, int, int, int, int, double> 
       (1, 1, 1, 1, 1, 1, 1, 1d); 

Auch wenn die IntelliSense-Dokumentation sagt, dass TRest ein Tuple sein muss. Sie erhalten keinen Fehler beim Schreiben oder Erstellen des Codes, er wird erst zur Laufzeit in Form einer ArgumentException angezeigt.

Sie können grob implementieren ein Tuple in ein paar Minuten, komplett mit einem Tuple-constrained 8. Element. Ich frage mich nur, warum es von der aktuellen Implementierung abgesehen wurde? Ist es möglicherweise ein Problem der Vorwärtskompatibilität, in dem sie mehr Elemente mit einer hypothetischen C# 5 hinzufügen könnten?

Kurzfassung grobe Implementierung

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; 
    } 
} 

...

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 
+0

Wirklich? Wie könnte man das so implementieren, dass das letzte Element als "Tupel" beliebiger Größe definiert wurde, ohne eine zusätzliche Basisklasse oder Schnittstelle zu definieren, die unter den verschiedenen generischen 'Tuple'-Größen üblich war? Ich sehe nicht, wie du denkst, dass sie das in C# machen könnten. – mquander

+1

@mquander, Tuple implementiert ITuple. Sie können einen eigenen Tuple-Typ (MyTuple) definieren, der das letzte Element an eine Schnittstelle bindet (IMyTuple), und Sie erhalten eine Kompilierungszeitüberprüfung. –

+2

Oh, ich wusste nichts über 'ITuple'. Danke für die Korrektur. Ich stelle fest, dass "ITuple" intern ist; vielleicht wollten sie es intern halten - wenn es eine Einschränkung wäre, müsste es öffentlich sein. – mquander

Antwort

1

Die hypothetische ITuple Einschränkung wäre es nicht wirklich beschränken sie ein Tupel sein [1], würde ? Nur eine Klasse, die ITuple implementiert.

[1] - Ich definiere "Tuple" als eine der BCL-Tuple<> Klassen.

+0

Das ist ein interessanter Punkt. Sie haben recht, jeder alte Typ könnte die Schnittstelle implementieren (was auch immer das beinhaltet) und die Anforderung der Einschränkung erfüllen. Aber dann schätze ich, dass es auch die Frage aufwirft, warum man den Typ zur Laufzeit einschränkt, man kann ein Tuple in irgendeinen der vorhandenen Slots legen, einfach sagen "wir machen eine 8-slotted (max) generische Klasse, benutze sie als Du siehst fit. " –

+1

Das ist der einzige Weg, um es wirklich als Tupel einzuschränken (Laufzeitprüfung für eine 'interne' Schnittstelle, also können wir es nicht implementieren). Der letzte Slot muss eigentlich ein Tupel sein, da er die Implementierung von 'Size',' GetHashCode', 'ToString' usw. beeinflusst. Er wird komplett anders behandelt als die anderen Slots. –

7

Es ist eine Beschränkung des Typsystems. ITuple ist eine interne Schnittstelle. Wenn es sich um eine generische Einschränkung handeln würde, müsste diese öffentlich sein, und dann würde jeder seine eigene ITuple implementieren, die nichts mit Tupeln zu tun haben könnte. Wenn man es auf intern beschränkt, kann das BCL-Team garantieren, dass es sich tatsächlich um eine Art Tupel handelt, was aber dazu führt, dass TRest etwas kompilierungssicherer ist als es sein könnte.

Verwandte Themen