2010-01-14 8 views
10

Einig speziellen CLI Typen von mscorlib Bibliothek (ArgIterator, TypedReference und RuntimeArgumentHandle Typen) kann nicht als generische Typ-Parameter verwendet werden, um die generischen Typen/Methoden zu konstruieren:C# Typparameter Spezifikation

void Foo<T>() { } 
void Bar() { Foo<ArgIterator>(); } 

liefert den Compiler-Fehler :

error CS0306: The type 'System.ArgIterator' may not be used as a type argument 

Aber dies ist nicht in der C# -Spezifikation dokumentiert.

Sind diese Typen Teil der CLI-Spezifikation oder werden diese Typen von der CLR-Implementierung bereitgestellt und sollte das oben beschriebene Verhalten nicht bei C# -Spezifikation dokumentiert werden?

+2

Und auch leer, nicht so überraschend. –

Antwort

10

First off, Jon ist wieder richtig - diese Jungs sind sehr spezielle Typen, deren Werte Objekt umgewandelt werden, und kann so nicht sein Wird als Typargument verwendet. Alle Typargumente müssen Typen sein, deren Werte in ein Objekt konvertiert werden können.

Ihre Frage zu Dokumentation beantworten:

Keine der Besonderheiten für variadische Methoden der Handhabung sind dokumentiert. Sie sind nicht Teil der C# -Sprache selbst - eine konforme Implementierung der Sprache ist nicht erforderlich, um Interoperabilität mit Sprachen herzustellen, die variadische Methoden unterstützen. Diese Features sind auch nicht in MSDN als Teil der Compilerdokumentation dokumentiert. Dies sind keine "offiziell unterstützten" Funktionen.

Das ist bedauerlich, aber es gibt nur so viel Budget zur Verfügung, und ich denke, die meisten Leute würden zustimmen, dass wir besser Features schreiben und Bugs beheben als Geld ausgeben Features, die buchstäblich 99,99% unserer Benutzer nie werden benutze sie immer, selbst wenn sie unterstützt wurden, was sie nicht sind.

Wenn Sie interoperabel in C# mit variadischen Methoden gehen wollen, sind Sie auf sich gestellt. Viel Glück!

+0

Ich habe mich geirrt, dass diese Features "offiziell" sind. Danke, Eric! :) – ControlFlow

6

Ich glaube, es ist, weil diese Typen "speziell" sind, dass sie nicht in object umgewandelt werden können; Nur Typen, die in object konvertiert werden können, können als Typargumente angegeben werden. Das gleiche gilt übrigens für Zeiger.

Ich kann nicht finden, wo dies dokumentiert ist (es ist für Hinweise in 4.4.1 dokumentiert), aber Eric Lippert erwähnte es in einem Kommentar neulich.

Ist dies nur eine Frage von Interesse, oder versuchen Sie, tatsächlich etwas mit dieser Art von Sache zu tun? tun?

+1

Natürlich ist dies nur Interesse und synthetisches Beispiel, ich habe einige generische Code mit allen Werttypen von mscorlib getestet und dieses Problem gegründet, aber keine Erklärung in C# spec gefunden ... Ich verstehe, dass diese Typen sind sehr spezielle, ArgIterator ist eigentlich eine Struktur mit unterschiedlicher Größe ... aber keine Erklärung! :) – ControlFlow

1

Alle drei Beispiele, die Sie angegeben haben, sind Strukturen und keine Klassen. Daher vermute ich, dass dies der Schlüssel zu diesem Problem ist. Ein Beispiel, das in der Dokumentation zu compiler error message enthalten ist, zeigt auch, dass es fehlschlagen würde, wenn Sie einen Zeiger auf einen Typ im generischen verwenden.

+0

Structs sind erlaubt und der ArgIterator enthält zum einen keine Zeiger. Ich habe versucht, eine benutzerdefinierte Struktur mit IntPtr Felder und das funktioniert gut. Kämpfen, um zu sehen, was den Fehler verursacht. Vielleicht hängt es mit den externen oder unsicheren Methoden zusammen. –

1

Abschnitt 8.2.4 der CLI spec ruft Werttypen auf, die Zeiger in den Auswertungsstapel "byref-like" -Typen enthalten können und sagt, dass sie nicht eingerahmt werden können. Sie nennt System.RuntimeArgumentHandle und System.TypedReference explizit als Beispiele für solche Typen, stellt jedoch keine erschöpfende Liste bereit. Abschnitt 9.4 führt weiter aus, dass byref-Typen, byref-ähnliche Typen und System.Void nicht zum Generieren von generischen Typen oder Methoden verwendet werden können.

1

Nur als Kommentar, hier ist ein weiterer Spaß, den Sie haben können, wenn Sie versuchen, Code mit diesem Typ zu kompilieren, der nicht in Objekt konvertiert werden kann. Alle Methoden hier kommen als Vorschläge von Visual Studio, wenn Sie die . (Punkt) eingeben.

ArgIterator.ReferenceEquals(new object(), new object()); // OK; static method inherited from System.Object 

    var strange = default(ArgIterator); 
    strange.End();   // OK; non-virtual method defined in the struct 
    strange.GetHashCode(); // OK; method overridden in the struct 
    strange.ToString();  // compile-time error; method overriden in System.ValueType, inherited but not overridden in the struct 
    strange.GetType();  // compile-time error; non-virtual method inherited from System.Object