2014-09-11 14 views
5

zu schreiben Ich stoße ziemlich oft auf die Notwendigkeit für kleine unveränderliche Datenstrukturen. Andere würden wahrscheinlich Tupel in diesen Fällen verwenden, aber ich mag es wirklich nicht, dass Tuples nicht gut lesen und nicht so viel Bedeutung ausdrücken. Ein Value2 von int sagt mir nichts.Kürzeste Möglichkeit, unveränderliche Struktur in C#

Ein Beispiel wäre das Erstellen einer Nachschlagetabelle (Dictionary) für eine Kombination von zwei Eigenschaften, d. H. Name und Rating.

Der kürzeste Weg, um eine unveränderliche Struktur für diese Fälle zu machen, die ich kenne, ist dies:

public struct Key 
{ 
    public string Name { get; private set; } 
    public int  Rating { get; private set; } 

    public LolCat(string name, int rating) : this() 
    { 
     Name = name; 
     Rating = rating; 
    } 
} 

// useage 
var key = new Key("MonorailCat", 5); 

Meiner Meinung nach viel es noch ‚syntaktischem Fett‘ ist in hier, dass Ich mag würde loswerden. Ich könnte es viel lesbarer machen, wenn ich nur Felder direkt aussetzen würde.

Ich mag die Syntax von diesem, weil es kaum syntaktisches Fett gibt. Der große Nachteil ist natürlich, dass es nicht unveränderlich ist, mit all seinen Gefahren.

Im Idealfall würde ich nur für dieses eine besondere Art haben möge, mit dem realen absoluten Minimum an Definition, wie:

public immutable struct Key 
{ 
    string Name; 
    int  Rating; 
} 

// useage (needs compiler magic) 
var key = new Key(Name: "MonorailCat", Rating: 5); 

Frage

Gibt es eine reale Welt Lösung etwas näher am Beispiel auf der Unterseite, um die Menge an syntaktischen Fett für eine sehr einfache unveränderliche Struktur zu reduzieren?

+0

Warum verwenden Sie in diesem Fall keine Klasse? – Kao

+0

Warum die Eigenschaften nicht als "readonly" -Felder verfügbar machen? Du würdest zumindest die '{get; private set;} '(und Sie benötigen immer noch den Konstruktor). – casperOne

Antwort

13

Ab C# 6 können Sie ziemlich kompakt schreiben struct initializers:

public struct Key 
{ 
    public string Name { get; } 
    public int Rating { get; } 

    public Key(string name, int rating) 
    { 
     this.Name = name; 
     this.Rating = rating; 
    } 
} 

... die deutlich zumindest kürzer. Ich würde dringend empfehlen, IEquatable<Key> zu implementieren, wohlgemerkt.

Beachten Sie, dass, wie Sie mit einer Struktur zu tun haben, können Sie noch in der Lage sein zu schreiben:

Key key = new Key(); 
Console.WriteLine(key.Rating); // 0 

... was aber kein Problem sein, aber in der Regel braucht zumindest berücksichtigen.

Bevor C# 6, würde ich gehen sogar noch länger als die aktuelle Code, um die Eigenschaften als schreibgeschützte Eigenschaften zu schreiben:

public struct Key 
{ 
    private readonly string name; 
    private readonly int rating; 

    public string Name { get { return name; } } 
    public int Rating { get { return rating; } } 

    public Key(string name, int rating) 
    { 
     this.name = name; 
     this.rating = rating; 
    } 
} 

ich dies klar „sein soll mehr fühlen unveränderlich "- wenn Sie eine beschreibbare Eigenschaft haben, selbst wenn der Setter nur privat ist, vermittelt das nicht den richtigen Eindruck IMO. (Obwohl es bemerkenswert ist, dass die Unveränderlichkeit in Structs immer ein kleines Bit eines Vorwands ist, vorausgesetzt, dass Sie this in Mitgliedern zuweisen können ...)

+0

Warum die Eigenschaften immer noch verwenden und die schreibgeschützten Felder nicht direkt wie in X.L verfügbar machen. Ameisen Beispiel? Nur für "Bedeutung"? –

+0

Ah macht nichts. Lesen Sie den Kommentar unter seiner Antwort. –

+0

@DirkBoer: Ich stelle ziemlich nie * Felder. Es fühlt sich für mich alle falsch an :) –

2

AFAIK, die kürzeste Sie nur lesbar verwendet schreiben kann, was kaum kürzer als Ihre Struktur ist Eigenschaften mit:

public struct Key 
{ 
    public readonly string Name; 
    public readonly int  Rating; 

    public Key(string name, int rating){ 
     Name = name; 
     Rating = rating; 
    } 
} 

var key = new Key("MonorailCat", 5); 
+1

Während das funktioniert, bedeutet es, die * Felder * und nicht die Eigenschaften offen zu legen - etwas, vor dem ich immer skeptisch bin. Insbesondere der Wechsel von dieser zu der eigenschaftsbasierten C# 6-Version ist eine bahnbrechende Änderung. –

+0

@JonSkeet Ich stimme Ihnen darin zu, aber ich weiß nicht, in welchem ​​Fall das Aussetzen von schreibgeschützten Feldern Probleme verursachen könnte (mit Ausnahme der von Ihnen erwähnten Umbruchänderung). Gibt es einen Fall, auf den ich achten sollte? –

+0

Abhängig von der Implementierung ist die UI-Bindung häufig nicht für Felder eingerichtet - und es gibt alle Arten von Bereichen in der Sprache, in denen die Unterschiede zwischen Eigenschaften und Feldern sehr subtil sind. Es ist nicht * so schlecht * wenn die Felder schreibgeschützt sind, aber ich persönlich würde immer noch lieber Eigenschaften verwenden. In meinen Augen sind Eigenschaften Teil der API zwischen einem Typ und seinen Clients; Felder sind ein Implementierungsdetail. (In Noda Time zum Beispiel habe ich kürzlich alles massiv neu implementiert - die Felder haben sich komplett geändert, aber die Eigenschaften sind die gleichen wie zuvor ...) –

1

In C# 7.2 gibt es eine Nur-Lese-Struktur.

readonly public struct ReadonlyPoint3D 
{ 
    public ReadonlyPoint3D(double x, double y, double z) 
    { 
     this.X = x; 
     this.Y = y; 
     this.Z = z; 
    } 
    //setters would not compile 
    public double X { get; } 
    public double Y { get; } 
    public double Z { get; } 

    private static ReadonlyPoint3D origin = new ReadonlyPoint3D(); 
    public static ref readonly ReadonlyPoint3D Origin => ref origin; 
    public ReadonlyPoint3D Scale(double factor) 
    { 
     /* all fail compilation 
     X *= factor; 
     Y *= factor; 
     Z *= factor; 
     */ 
     return new ReadonlyPoint3D(X * factor, Y * factor, Z * factor); 
    } 
} 

Der Compiler erzwingt, dass alle Mitglieder schreibgeschützt sind. Dies wurde als 'in' Referenz statt Kopie des Empfängers, die in der Regel effizienter ist.

Reference

+0

+1, obwohl ich sagen würde "das ist normalerweise effizienter". Es gibt ein paar Mal, wenn es weniger ist. In der Regel können Sie im Allgemeinen froh sein, dass es die meiste Zeit effizienter ist, aber wenn Sie versuchen, einen Hotspot zu optimieren, in dem dieser Hotspot eine interne readonly-Struktur verwendet, dann ist eines der Dinge, die es wert sind, das Profil zu lesen. –

+0

Danke. Einverstanden. Geändert. – acarlon

Verwandte Themen