Ich weiß, ich weiß ... Eric Lipperts Antwort auf diese Art von Frage lautet normalerweise " weil es die Kosten für das Entwerfen, Implementieren, Testen und Dokumentieren nicht wert war ".
Trotzdem möchte ich eine bessere Erklärung ... Ich habe diesen Blog-Beitrag über neue C # 4-Funktionen gelesen und im Abschnitt über COM Interop hat der folgende Teil meine Aufmerksamkeit erregt:
Übrigens verwendet dieser Code eine weitere neue Funktion: indizierte Eigenschaften (sehen Sie sich diese eckigen Klammern nach Range genauer an.) Diese Funktion ist jedoch nur für COM-Interop verfügbar. Sie können in C # 4.0 keine eigenen indizierten Eigenschaften erstellen .
OK, aber warum ? Ich wusste bereits und bedauerte, dass es nicht möglich war, indizierte Eigenschaften in C # zu erstellen, aber dieser Satz ließ mich noch einmal darüber nachdenken. Ich sehe mehrere gute Gründe, es umzusetzen:
- Die CLR unterstützt dies (
PropertyInfo.GetValue
hat beispielsweise einenindex
Parameter), daher ist es schade, dass wir es in C # nicht nutzen können - Es wird für COM-Interop unterstützt, wie im Artikel gezeigt (unter Verwendung des dynamischen Versands).
- Es ist in VB.NET implementiert
- Es ist bereits möglich, Indexer zu erstellen, dh einen Index auf das Objekt selbst anzuwenden. Daher wäre es wahrscheinlich keine große Sache, die Idee auf Eigenschaften auszudehnen, dieselbe Syntax beizubehalten und nur durch
this
einen Eigenschaftsnamen zu ersetzen
Es würde erlauben, solche Dinge zu schreiben:
public class Foo
{
private string[] _values = new string[3];
public string Values[int index]
{
get { return _values[index]; }
set { _values[index] = value; }
}
}
Derzeit besteht die einzige mir bekannte Problemumgehung darin, eine innere Klasse ( ValuesCollection
zum Beispiel) zu erstellen , die einen Indexer implementiert, und die Values
Eigenschaft so zu ändern , dass eine Instanz dieser inneren Klasse zurückgegeben wird.
Das ist sehr einfach, aber nervig ... Vielleicht könnte der Compiler es für uns tun! Eine Option wäre, eine innere Klasse zu generieren, die den Indexer implementiert, und ihn über eine öffentliche generische Schnittstelle verfügbar zu machen:
// interface defined in the namespace System
public interface IIndexer<TIndex, TValue>
{
TValue this[TIndex index] { get; set; }
}
public class Foo
{
private string[] _values = new string[3];
private class <>c__DisplayClass1 : IIndexer<int, string>
{
private Foo _foo;
public <>c__DisplayClass1(Foo foo)
{
_foo = foo;
}
public string this[int index]
{
get { return _foo._values[index]; }
set { _foo._values[index] = value; }
}
}
private IIndexer<int, string> <>f__valuesIndexer;
public IIndexer<int, string> Values
{
get
{
if (<>f__valuesIndexer == null)
<>f__valuesIndexer = new <>c__DisplayClass1(this);
return <>f__valuesIndexer;
}
}
}
Aber in diesem Fall würde die Eigenschaft natürlich tatsächlich a zurückgeben IIndexer<int, string>
und wäre nicht wirklich eine indizierte Eigenschaft ... Es wäre besser, eine echte CLR-indizierte Eigenschaft zu generieren.
Was denken Sie ? Möchten Sie diese Funktion in C # sehen? Wenn nicht, warum?
quelle
Antworten:
So haben wir C # 4 entworfen.
Zuerst haben wir eine Liste aller möglichen Funktionen erstellt, die wir der Sprache hinzufügen könnten.
Dann haben wir die Funktionen in "Das ist schlecht, wir dürfen es niemals tun", "Das ist großartig, wir müssen es tun" und "Das ist gut, aber diesmal wollen wir es nicht tun" zusammengefasst.
Dann haben wir uns angesehen, wie viel Budget wir für das Entwerfen, Implementieren, Testen, Dokumentieren, Versenden und Warten der "Muss" -Funktionen benötigen, und festgestellt, dass wir 100% über dem Budget liegen.
Also haben wir ein paar Sachen aus dem "Muss" -Eimer in den "Schön zu haben" -Eimer verschoben.
Indizierte Eigenschaften waren nie irgendwo in der Nähe der Spitze der Liste „Muss ich haben“. Sie sind sehr niedrig auf der "netten" Liste und flirten mit der "schlechten Idee" Liste.
Jede Minute, die wir mit dem Entwerfen, Implementieren, Testen, Dokumentieren oder Verwalten von netten Funktionen X verbringen, ist eine Minute, die wir nicht mit fantastischen Funktionen A, B, C, D, E, F und G verbringen können. Wir müssen rücksichtslos Prioritäten setzen, damit wir nur die bestmöglichen Funktionen ausführen. Indizierte Eigenschaften wären nett, aber nett ist nicht annähernd gut genug, um tatsächlich implementiert zu werden.
quelle
Der AC # -Indexer ist eine indizierte Eigenschaft. Es ist
Item
standardmäßig benannt (und Sie können es beispielsweise von VB als solches bezeichnen), und Sie können es mit IndexerNameAttribute ändern, wenn Sie möchten.Ich bin mir nicht sicher, warum es speziell so entworfen wurde, aber es scheint eine absichtliche Einschränkung zu sein. Es steht jedoch im Einklang mit den Framework Design Guidelines, die den Ansatz einer nicht indizierten Eigenschaft empfehlen, die ein indizierbares Objekt für Mitgliedssammlungen zurückgibt. Dh "indexierbar sein" ist ein Merkmal eines Typs; Wenn es auf mehrere Arten indizierbar ist, sollte es wirklich in mehrere Typen aufgeteilt werden.
quelle
Da Sie dies bereits tun können und gezwungen sind, über OO-Aspekte nachzudenken, würde das Hinzufügen indizierter Eigenschaften der Sprache nur mehr Rauschen hinzufügen. Und nur eine andere Möglichkeit, etwas anderes zu tun.
Ich persönlich würde es vorziehen, nur einen einzigen Weg zu sehen, etwas zu tun, anstatt 10 Wege. Aber das ist natürlich eine subjektive Meinung.
quelle
Früher habe ich die Idee der indizierten Eigenschaften favorisiert, aber dann wurde mir klar, dass dies schreckliche Mehrdeutigkeiten hinzufügen und die Funktionalität tatsächlich beeinträchtigen würde . Indizierte Eigenschaften würden bedeuten, dass Sie keine untergeordnete Sammlungsinstanz haben. Das ist sowohl gut als auch schlecht. Die Implementierung ist weniger schwierig und Sie benötigen keinen Verweis auf die einschließende Eigentümerklasse. Es bedeutet aber auch, dass Sie diese untergeordnete Sammlung an nichts weitergeben können. Sie müssten wahrscheinlich jedes Mal aufzählen. Sie können es auch nicht tun. Am schlimmsten ist, dass Sie anhand einer indizierten Eigenschaft nicht erkennen können, ob es sich um diese oder eine Sammlungseigenschaft handelt.
Die Idee ist rational, führt aber nur zu Inflexibilität und abrupter Unbeholfenheit.
quelle
Bar
. B. ]. Der AusdruckThing.Bar(5)
würde die indizierte EigenschaftBar
für verwendenThing
, während er(Thing.Bar)(5)
die nicht indizierte Eigenschaft verwendenBar
und dann den Standardindexer des resultierenden Objekts verwenden würde. Für mich ist esThing.Bar[5]
gut , zuzulassen, dass es eine Eigenschaft vonThing
und keine Eigenschaft vonThing.Bar
ist, da es unter anderem möglich ist, dass zu einem bestimmten Zeitpunkt die Bedeutung vonThing.Bar[4]
klar ist, aber die richtige Wirkung von ...var temp=Thing.Bar; do_stuff_with_thing; var q=temp[4]
mag unklar sein. Betrachten Sie auch den Begriff,Thing
der die DatenBar
in einem Feld enthalten könnte, das entweder ein gemeinsames unveränderliches Objekt oder ein nicht gemeinsam genutztes veränderbares Objekt sein könnte. Ein Versuch, zu schreiben,Bar
wenn das Hintergrundfeld unveränderlich ist, sollte eine veränderbare Kopie erstellen, ein Versuch, daraus zu lesen, jedoch nicht. WennBar
es sich um eine benannte indizierte Eigenschaft handelt, kann der indizierte Getter die Hintergrundsammlung in Ruhe lassen (ob veränderbar oder nicht), während der Setter bei Bedarf eine neue veränderbare Kopie erstellen kann.Ich finde das Fehlen indizierter Eigenschaften sehr frustrierend, wenn ich versuche, sauberen, präzisen Code zu schreiben. Eine indizierte Eigenschaft hat eine ganz andere Konnotation als die Bereitstellung einer indizierten Klassenreferenz oder die Bereitstellung einzelner Methoden. Ich finde es etwas beunruhigend, dass die Bereitstellung des Zugriffs auf ein internes Objekt, das eine indizierte Eigenschaft implementiert, sogar als akzeptabel angesehen wird, da dies häufig eine der Schlüsselkomponenten der Objektorientierung verletzt: die Kapselung.
Ich bin oft genug auf dieses Problem gestoßen, aber ich bin es heute gerade wieder aufgetreten, daher werde ich ein reales Codebeispiel bereitstellen. Die Schnittstelle und Klasse, die geschrieben wird, speichert die Anwendungskonfiguration, bei der es sich um eine Sammlung lose verwandter Informationen handelt. Ich musste benannte Skriptfragmente hinzufügen und die Verwendung des unbenannten Klassenindexers hätte einen sehr falschen Kontext impliziert, da Skriptfragmente nur ein Teil der Konfiguration sind.
Wenn indizierte Eigenschaften in C # verfügbar wären, hätte ich den folgenden Code implementieren können (Syntax ist, dass dieser [Schlüssel] in PropertyName [Schlüssel] geändert wurde).
Leider sind indizierte Eigenschaften nicht implementiert, daher habe ich eine Klasse zum Speichern implementiert und Zugriff darauf gewährt. Dies ist eine unerwünschte Implementierung, da der Zweck der Konfigurationsklasse in diesem Domänenmodell darin besteht, alle Details zu kapseln. Clients dieser Klasse greifen namentlich auf bestimmte Skriptfragmente zu und haben keinen Grund, diese zu zählen oder aufzuzählen.
Ich hätte dies umsetzen können als:
Was ich wahrscheinlich haben sollte, aber dies ist ein nützliches Beispiel dafür, warum die Verwendung von indizierten Klassen als Ersatz für diese fehlende Funktion oft kein vernünftiger Ersatz ist.
Um eine ähnliche Funktion wie eine indizierte Eigenschaft zu implementieren, musste ich den folgenden Code schreiben, der erheblich länger, komplexer und daher schwerer zu lesen, zu verstehen und zu warten ist.
quelle
Eine weitere Problemumgehung finden Sie unter Einfache Erstellung von Eigenschaften, die die Indizierung in C # unterstützen und weniger Arbeit erfordern.
EDIT : Ich sollte auch hinzufügen, dass als Antwort auf die ursprüngliche Frage, dass meine, wenn wir die gewünschte Syntax mit Bibliotheksunterstützung erreichen können, es einen sehr starken Fall geben muss, um sie direkt zur Sprache hinzuzufügen, um dies zu tun Minimieren Sie das Aufblähen der Sprache.
quelle
this[]
) vorhanden. Sie müssen lediglich einen Bezeichner anstelle von zulassenthis
. Aber ich bezweifle, dass es jemals in die Sprache aufgenommen wird, aus den Gründen, die Eric in seiner Antwort erklärt hatNun, ich würde sagen, dass sie es nicht hinzugefügt haben, weil es die Kosten für das Entwerfen, Implementieren, Testen und Dokumentieren nicht wert war.
Scherz beiseite, es liegt wahrscheinlich daran, dass die Problemumgehungen einfach sind und die Funktion niemals die Zeit im Vergleich zum Nutzen verkürzt. Es würde mich nicht wundern, wenn dies auf der ganzen Linie als Veränderung erscheint.
Sie haben auch vergessen zu erwähnen, dass eine einfachere Problemumgehung nur eine reguläre Methode ist:
quelle
Es gibt eine einfache allgemeine Lösung, bei der Lambdas zum Proxy der Indizierungsfunktion verwendet werden
Für schreibgeschützte Indizierung
Zur veränderlichen Indizierung
und eine Fabrik
in meinem eigenen Code benutze ich es gerne
und mit einer Instanz von MoineauFlankContours kann ich tun
quelle
Ich habe auch selbst herausgefunden, dass Sie explizit implementierte Schnittstellen verwenden können, um dies zu erreichen, wie hier gezeigt: Benannte indizierte Eigenschaft in C #? (Siehe den zweiten Weg in dieser Antwort)
quelle