2009-11-16 5 views
7

In C# gibt es die "Standard" Initialisierungstechnik {Property1 = "a", Property2 = "b"}, und es gibt ein paar spezielle Varianten für Sammlungen (Liste und Wörterbuch). {Wert1, Wert2} und {{"Schlüssel1", Wert1}, {"Schlüssel2", Wert2}}.Gibt es in C# eine Möglichkeit, benutzerdefinierte Objektinitialisierer für neue Datentypen zu schreiben?

Ich hätte gerne einen rekursiven Objektinitialisierer für einen Baum-Datentyp, aber ich weiß nicht, ob es eine Möglichkeit gibt, diesen Mechanismus anzupassen. Ich hätte gerne etwas, das wie ein S-Ausdruck aussieht. {item1 {item2 item3 item4} {item5 item6}}

Ich mache das über Konstruktoren, aber ich hätte gerne eine Terser-Syntax.

Antwort

11

Wenn Sie den ICollection IEnumerable implementieren Schnittstelle und haben eine Methode namens add. Übrigens ist dies alles in der ICollection-Schnittstelle enthalten, weshalb ich es verwechselt habe.

Test test = new Test() { 
    new Test2() { 
     new Test3() { 

     } 
    }, 
    new Test() { 
     new Test2() { 
      { new Test(), new Test2() }, 
      { new Test(), new Test2() }, 
      { new Test(), new Test2() } 
     } 
    } 
}; 

public class Test : IEnumerable 
{ 
    public void Add(Test a){} 
    public void Add(Test2 a){} 
    public IEnumerator GetEnumerator(){} 
} 

public class Test2 : IEnumerable 
{ 
    public void Add(Test a, Test2 b){} 
    public void Add(Test3 a){} 
    public IEnumerator GetEnumerator(){} 
} 

public class Test3 : IEnumerable 
{ 
    public void Add(Test a) {} 
    public void Add(Test2 a){} 
    public IEnumerator GetEnumerator(){} 
} 
+1

Sie müssen ICollection nicht implementieren - nur IEnumerable –

+0

Das ist nicht ganz so knapp wie das, was ich mir vorgestellt habe, aber es sieht so aus, als ob es so nah wie möglich ist .. Es sieht so aus, als ob die Antwort darauf ist passen Sie den Objektinitialisierungsmechanismus wirklich an, aber Sie können auf die integrierte IEnumerable-Initialisierungsunterstützung piggyback. – darthtrevino

+0

Found ein Blogpost, der dieses http://resharper.blogspot.com/2 diskutiert 007/09/c-30-collection-initializers-incomplete.html – darthtrevino

4

ein variadic lokales Lambda n verwenden, die einfach Ihren Konstruktor aufruft, könnte man es als so kurz kommen:

n(item1, n(item2, item3, item4), n(item5, item6)) 

Update: so etwas wie

var n = (params Node[] nodes) => new Node(nodes); 
+2

Warum nicht einfach nur Params sagen? Dies ist eine C# -Frage. – ChaosPandion

+0

Schnelle Antwort! Das ist eine ziemlich interessante Lösung, aber es würde erfordern, das Lambda zu definieren, wann immer ich eine Initialisierung durchführen möchte. Außerdem würde es erfordern, dass alle variablen Parameter entweder Elemente oder Bäume von Elementen sind, nicht beide gemischt (zB n (Element1, N (Element2, Element3), Element4) wäre nicht möglich. – darthtrevino

+0

Sie können das Lambda definieren einmal und erstellen Sie einen lokalen Verweis darauf, wenn Sie die kürzere Syntax benötigen.Hilft ein wenig.Wenn Ihre Strukturelemente nicht selbst Knoten sind, können Sie das Lambda ändern, um ein allgemeines 'Objekt []' zu akzeptieren und etwas Magie darauf zu tun. – Thomas

1

Wenn die Knoten des Baumes sind leicht zu konstruieren, dh sie kann von ihrem Wert initialisiert werden, dann kann man Dinge machen knappere als ChaosPandion Antwort, indem eine zusätzliche Methode hinzu:

class Tree : IEnumerable 
{ 
    public string Value { get; set; } 

    public void Add(Tree t) { ... } 

    // Add this method 
    public void Add(string s) 
    { 
     Add(new Tree { Value = s }); 
    } 

    public IEnumerator GetEnumerator() { ... } 
} 

So :

{ item1 { item2 item3 item4 } { item5 item6 } } 

Becomes:

new Tree { "item1", new Tree { "item2", "item3", "item4" }, new Tree { "item5", "item6" } }; 
Verwandte Themen