Nachdem Sie Folgendes nicht kompiliert haben:
public class Gen<T> where T : System.Array
{
}
mit dem Fehler
Eine Einschränkung kann keine spezielle Klasse "System.Array" sein.
Ich begann fragen, was genau ist eine „Sonderklasse“?
Menschen scheinen oft die gleiche Art von Fehler zu bekommen, wenn sie System.Enum
in einer generischen Einschränkung angeben . Ich habe die gleichen Ergebnisse mit System.Object
, System.Delegate
, System.MulticastDelegate
und System.ValueType
auch.
Gibt es noch mehr davon? Ich kann keine Informationen zu "Sonderklassen" in C # finden.
Was ist an diesen Klassen so besonders, dass wir sie nicht als generische Typeinschränkung verwenden können?
c#
class
generics
generic-constraints
Mints97
quelle
quelle
System.Object
es sich nicht um eine "Sonderklasse" handelt, da dies gültig istpublic class X : System.Object { }
, sondernSystem.Object
immer noch um eine "Sonderklasse".Antworten:
Aus dem Roslyn-Quellcode geht hervor, dass es sich um eine Liste fest codierter Typen handelt:
Quelle: Binder_Constraints.cs IsValidConstraintType
Ich habe es mithilfe einer GitHub-Suche gefunden: "Eine Einschränkung kann keine spezielle Klasse sein."
quelle
CS0702
.object
), oder zumindest hat es etwas damit zu tun. Auchwhere T : Array
würde es ermöglichen Assay als T vorbei, die wahrscheinlich nicht ist , was die meisten Leute wollen.Ich fand einen Kommentar von Jon Skeet aus dem Jahr 2008 zu einer ähnlichen Frage: Warum wird die
System.Enum
Einschränkung nicht unterstützt ?Ich weiß, dass dies ein wenig vom Thema abweicht , aber er fragte Eric Lippert (das C # -Team) danach und sie gaben diese Antwort:
quelle
Laut MSDN handelt es sich um eine statische Liste von Klassen:
Compilerfehler CS0702
Einschränkung kann keine spezielle Klasse 'bezeichner' sein Die folgenden Typen dürfen nicht als Einschränkungen verwendet werden:
quelle
System.MulticastDelegate
in der Liste?Gemäß C # 4.0-Sprachspezifikation (codiert: [10.1.5] Typparametereinschränkungen) werden zwei Dinge gesagt:
Wenn Sie eine generische Klasse definieren, können Sie Einschränkungen auf die Arten von Typen anwenden, die Clientcode für Typargumente verwenden kann, wenn er Ihre Klasse instanziiert. Wenn der Clientcode versucht, Ihre Klasse mithilfe eines Typs zu instanziieren, der von einer Einschränkung nicht zugelassen wird, ist das Ergebnis ein Fehler bei der Kompilierung. Diese Einschränkungen werden als Einschränkungen bezeichnet. Einschränkungen werden mithilfe des Schlüsselworts where contextual angegeben. Wenn Sie einen generischen Typ als Referenztyp einschränken möchten, verwenden Sie: class.
Dies verhindert, dass der generische Typ ein Werttyp ist, wie z. B. int oder eine Struktur usw.
Außerdem kann die Einschränkung keine spezielle Klassen-ID sein. Die folgenden Typen dürfen nicht als Einschränkungen verwendet werden:
quelle
Es gibt bestimmte Klassen im Framework, die spezielle Merkmale effektiv an alle von ihnen abgeleiteten Typen weitergeben, diese Merkmale jedoch selbst nicht besitzen . Die CLR selbst schreibt nicht vor, diese Klassen als Einschränkungen zu verwenden, aber auf sie beschränkte generische Typen würden die nicht vererbten Merkmale nicht wie konkrete Typen erhalten. Die Entwickler von C # entschieden, dass sie solche Einschränkungen verbieten sollten, anstatt ihnen zu erlauben, sich so zu verhalten, wie sie es in der CLR tun, da ein solches Verhalten einige Menschen verwirren könnte und sie keinen Nutzen daraus ziehen konnten.
Wenn man zum Beispiel schreiben darf :
void CopyArray<T>(T dest, T source, int start, int count)
; man könnte Methodendest
undsource
Methoden übergeben, die ein Argument vom Typ erwartenSystem.Array
; Ferner würde eine Kompilierung-Validierung , dass bekommendest
undsource
waren die kompatibelen Array - Typen, aber man würde nicht dem Zugriff auf Elemente des Arrays mit der Lage sein[]
Bediener.Die Unfähigkeit,
Array
als Einschränkung zu verwenden, ist meistens recht einfach zu umgehen, da diesvoid CopyArray<T>(T[] dest, T[] source, int start, int count)
in fast allen Situationen funktioniert, in denen die erstere Methode funktionieren würde. Es hat jedoch eine Schwäche: Die erstere Methode würde in dem Szenario funktionieren, in dem eines oder beide der Argumente vom Typ waren,System.Array
während Fälle zurückgewiesen wurden, in denen die Argumente inkompatible Array-Typen sind. Durch Hinzufügen einer Überladung, bei der beide Argumente vom Typ waren,System.Array
würde der Code die zusätzlichen Fälle akzeptieren, die er akzeptieren sollte, aber auch fälschlicherweise Fälle akzeptieren, die er nicht akzeptieren sollte.Ich finde die Entscheidung, die meisten besonderen Einschränkungen zu verbieten, lästig. Die einzige, die keine semantische Bedeutung haben würde, wäre
System.Object
[denn wenn dies als Einschränkung legal wäre, würde alles sie erfüllen].System.ValueType
Dies wäre wahrscheinlich nicht sehr nützlich, da Referenzen vom TypValueType
nicht wirklich viel mit Werttypen gemeinsam haben, aber in Fällen, in denen es um Reflexion geht, plausibel einen gewissen Wert haben könnten. BeideSystem.Enum
undSystem.Delegate
hätten einige echte Verwendungszwecke, aber da die Macher von C # nicht an sie gedacht haben, sind sie ohne guten Grund verboten.quelle
Folgendes kann in CLR über C # 4th Edition gefunden werden:
Primäre Einschränkungen
Ein Typparameter kann null primäre Einschränkungen oder eine primäre Einschränkung angeben. Eine primäre Einschränkung kann ein Referenztyp sein, der eine Klasse identifiziert, die nicht versiegelt ist. Sie können keinen der folgenden speziellen Referenztypen angeben: System.Object , System.Array , System.Delegate , System.MulticastDelegate , System.ValueType , System.Enum oder System.Void . Wenn Sie eine Einschränkung für den Referenztyp angeben, versprechen Sie dem Compiler, dass ein angegebenes Typargument entweder vom gleichen Typ oder von einem vom Einschränkungstyp abgeleiteten Typ ist.
quelle
System.Array
,System.Delegate
,System.MulticastDelegate
,System.Enum
, oderSystem.ValueType
. Darüber hinaus kann eine generische Klassendeklaration nichtSystem.Attribute
als direkte oder indirekte Basisklasse verwendet werden.Ich glaube nicht, dass es eine offizielle Definition von "Sonderklassen" / "Sondertypen" gibt.
Sie können über sie als Typen nachdenken, die nicht mit der Semantik "regulärer" Typen verwendet werden können:
PS Ich würde
System.Void
der Liste hinzufügen .quelle
System.Void
gibt einen ganz anderen Fehler, wenn als generische Einschränkung verwendet =)void
ganz besonders. :)System.Array
kann Methoden verwendenArray.Copy
, um Daten von einem zum anderen zu verschieben. Code mit den Parametern eines Typs gezwungen zu derSystem.Delegate
Lage wäre , zu verwenden ,Delegate.Combine
auf sie und warf das Ergebnis in den richtigen Typ . Wenn Sie einen generischen bekannten Typ effektiv nutzen,Enum
wird Reflection für jeden dieser Typen einmal verwendet. Eine generischeHasAnyFlag
Methode kann jedoch 10x schneller sein als eine nicht generische Methode.