Was sind einige Beispiele für MemberBinding LINQ-Ausdrücke?

.net c# expression-trees linq

Frage

Es gibt drei Möglichkeiten, aber ich kann keine Beispiele finden:

  1. System.Linq.Expressions.MemberAssignment
  2. System.Linq.Expressions.MemberListBinding
  3. System.Linq.Expressions.MemberMemberBinding

Ich möchte einige Komponententests schreiben, um zu sehen, ob ich mit ihnen umgehen kann, aber ich weiß nicht, wie ich sie schreiben soll, bis auf die erste, die neu zu sein scheint new Foo { Property = "value" } wo Property = "value" ist ein Ausdruck vom Typ MemberAssignment .

Siehe auch diesen MSDN-Artikel .

Akzeptierte Antwort

EDIT Dies ersetzt die vorherige Antwort als Reaktion auf den ersten Kommentar.

Die Klassen, die ich in diesen Beispielen verwende, sind wie folgt:

public class Node
{
  //initialise non-null, so we can use the MemberMemberBinding
  private NodeData _data = new NodeData();
  public NodeData Data { get { return _data; } set { _data = value; } }
  //initialise with one element so you can see how a MemberListBind
  //actually adds elements to those in a list, not creating it new.
  //Note - can't set the element to 'new Node()' as we get a Stack Overflow!
  private IList<Node> _children = new List<Node>() { null };
  public IList<Node> Children 
    { get { return _children; } set { _children = value; } }
}

public class NodeData
{
  private static int _counter = 0;
  //allows us to count the number of instances being created.
  public readonly int ID = ++_counter;
  public string Name { get; set; }
}

Erstens können Sie den C # -Compiler dazu bringen, Ausdrücke zu generieren, damit Sie mehr herausfinden können, wie sie funktionieren, indem Sie Folgendes tun:

public class Node
{
  //initialise non-null, so we can use the MemberMemberBinding
  private NodeData _data = new NodeData();
  public NodeData Data { get { return _data; } set { _data = value; } }
  //initialise with one element so you can see how a MemberListBind
  //actually adds elements to those in a list, not creating it new.
  //Note - can't set the element to 'new Node()' as we get a Stack Overflow!
  private IList<Node> _children = new List<Node>() { null };
  public IList<Node> Children 
    { get { return _children; } set { _children = value; } }
}

public class NodeData
{
  private static int _counter = 0;
  //allows us to count the number of instances being created.
  public readonly int ID = ++_counter;
  public string Name { get; set; }
}

Generiert einen Inline-Ausdruck, der einen Aufruf von Expression.New , und übergibt die ConstructorInfo des Knotentyps. Öffnen Sie die Ausgabe-DLL in Reflector, um zu sehen, was ich meine.

Ich sollte zuerst erwähnen, dass diese drei Ausdrücke, die Sie fragen, normalerweise in einem MemberBinding [] - Array in einem Expression.New übergeben werden oder ineinander eingebettet sind (da Member-Initialisierer von Natur aus rekursiv sind).

Auf zum Grundstück ...

MitgliedAusrichtung

Der MemberAssignment-Ausdruck repräsentiert die Einstellung eines einzelnen Members einer neuen Instanz mit dem Rückgabewert eines bestimmten Ausdrucks. Es wird im Code mit der Factory-Methode " Expression.Bind " erstellt. Dies ist das am häufigsten anzutreffende Zeichen. In C # -Code entspricht dies dem Folgenden:

public class Node
{
  //initialise non-null, so we can use the MemberMemberBinding
  private NodeData _data = new NodeData();
  public NodeData Data { get { return _data; } set { _data = value; } }
  //initialise with one element so you can see how a MemberListBind
  //actually adds elements to those in a list, not creating it new.
  //Note - can't set the element to 'new Node()' as we get a Stack Overflow!
  private IList<Node> _children = new List<Node>() { null };
  public IList<Node> Children 
    { get { return _children; } set { _children = value; } }
}

public class NodeData
{
  private static int _counter = 0;
  //allows us to count the number of instances being created.
  public readonly int ID = ++_counter;
  public string Name { get; set; }
}

oder

public class Node
{
  //initialise non-null, so we can use the MemberMemberBinding
  private NodeData _data = new NodeData();
  public NodeData Data { get { return _data; } set { _data = value; } }
  //initialise with one element so you can see how a MemberListBind
  //actually adds elements to those in a list, not creating it new.
  //Note - can't set the element to 'new Node()' as we get a Stack Overflow!
  private IList<Node> _children = new List<Node>() { null };
  public IList<Node> Children 
    { get { return _children; } set { _children = value; } }
}

public class NodeData
{
  private static int _counter = 0;
  //allows us to count the number of instances being created.
  public readonly int ID = ++_counter;
  public string Name { get; set; }
}

MemberMemberBinding

Die MemberMemberBinding stellt die Inline-Initialisierung der Member eines Members dar, das bereits initialisiert ist (dh newed oder eine Struktur, die nicht null sein kann). Es wird durch Expression.MemberBind und stellt nicht das Erstellen einer neuen Instanz dar . Daher unterscheidet es sich von der MemberBind-Methode, indem keine ConstructorInfo verwendet wird, sondern ein Verweis auf eine Property Get-Methode (Property Accessor). Daher führt ein Versuch, ein Member auf diese Weise zu initialisieren, das mit Null beginnt, zu einer NullReferenceException.

Um dies im Code zu generieren, tun Sie Folgendes:

public class Node
{
  //initialise non-null, so we can use the MemberMemberBinding
  private NodeData _data = new NodeData();
  public NodeData Data { get { return _data; } set { _data = value; } }
  //initialise with one element so you can see how a MemberListBind
  //actually adds elements to those in a list, not creating it new.
  //Note - can't set the element to 'new Node()' as we get a Stack Overflow!
  private IList<Node> _children = new List<Node>() { null };
  public IList<Node> Children 
    { get { return _children; } set { _children = value; } }
}

public class NodeData
{
  private static int _counter = 0;
  //allows us to count the number of instances being created.
  public readonly int ID = ++_counter;
  public string Name { get; set; }
}

Dies mag ein wenig seltsam erscheinen, aber was hier passiert ist, dass die Eigenschaft get-Methode für Data ausgeführt wird, um einen Verweis auf das bereits initialisierte Element zu erhalten. In diesem Fall werden die inneren MemberBindings der Reihe nach ausgeführt, so dass der obige Code Daten nicht überschreibt, sondern folgendermaßen:

public class Node
{
  //initialise non-null, so we can use the MemberMemberBinding
  private NodeData _data = new NodeData();
  public NodeData Data { get { return _data; } set { _data = value; } }
  //initialise with one element so you can see how a MemberListBind
  //actually adds elements to those in a list, not creating it new.
  //Note - can't set the element to 'new Node()' as we get a Stack Overflow!
  private IList<Node> _children = new List<Node>() { null };
  public IList<Node> Children 
    { get { return _children; } set { _children = value; } }
}

public class NodeData
{
  private static int _counter = 0;
  //allows us to count the number of instances being created.
  public readonly int ID = ++_counter;
  public string Name { get; set; }
}

Aus diesem Grund ist dieser Ausdruckstyp erforderlich, denn wenn Sie mehrere Eigenschaftswerte festlegen müssen, können Sie dies nicht in einem Einzeiler tun, es sei denn, es gibt einen speziellen Ausdruck / eine spezielle Syntax. Wenn NodeData über ein anderes Zeichenfolgenelement ( OtherName ) verfügt, das Sie gleichzeitig OtherName , ohne Initialisierungssyntax / -ausdrücke, müssen Sie Folgendes tun:

public class Node
{
  //initialise non-null, so we can use the MemberMemberBinding
  private NodeData _data = new NodeData();
  public NodeData Data { get { return _data; } set { _data = value; } }
  //initialise with one element so you can see how a MemberListBind
  //actually adds elements to those in a list, not creating it new.
  //Note - can't set the element to 'new Node()' as we get a Stack Overflow!
  private IList<Node> _children = new List<Node>() { null };
  public IList<Node> Children 
    { get { return _children; } set { _children = value; } }
}

public class NodeData
{
  private static int _counter = 0;
  //allows us to count the number of instances being created.
  public readonly int ID = ++_counter;
  public string Name { get; set; }
}

Was ist kein One Liner - aber das ist:

public class Node
{
  //initialise non-null, so we can use the MemberMemberBinding
  private NodeData _data = new NodeData();
  public NodeData Data { get { return _data; } set { _data = value; } }
  //initialise with one element so you can see how a MemberListBind
  //actually adds elements to those in a list, not creating it new.
  //Note - can't set the element to 'new Node()' as we get a Stack Overflow!
  private IList<Node> _children = new List<Node>() { null };
  public IList<Node> Children 
    { get { return _children; } set { _children = value; } }
}

public class NodeData
{
  private static int _counter = 0;
  //allows us to count the number of instances being created.
  public readonly int ID = ++_counter;
  public string Name { get; set; }
}

Wo das Data = Bit ist, ist die MemberMemberBinding.

Ich hoffe, das ist klar!

MemberListBinding

Erstellt von der Expression.ListBind Methode (erfordert auch Aufrufe von Expression.ElementInit ), ähnelt dies der MemberMemberBinding (indem das Member eines Objekts nicht neu erstellt wird), aber diesmal ist es eine Instanz von ICollection / IList hinzugefügt mit Inline-Elementen .:

public class Node
{
  //initialise non-null, so we can use the MemberMemberBinding
  private NodeData _data = new NodeData();
  public NodeData Data { get { return _data; } set { _data = value; } }
  //initialise with one element so you can see how a MemberListBind
  //actually adds elements to those in a list, not creating it new.
  //Note - can't set the element to 'new Node()' as we get a Stack Overflow!
  private IList<Node> _children = new List<Node>() { null };
  public IList<Node> Children 
    { get { return _children; } set { _children = value; } }
}

public class NodeData
{
  private static int _counter = 0;
  //allows us to count the number of instances being created.
  public readonly int ID = ++_counter;
  public string Name { get; set; }
}

Also, diese letzten beiden Ausdrücke sind ein bisschen Randfälle, aber sicherlich sind Dinge, auf die Sie gut stoßen könnten, da sie offensichtlich sehr nützlich sind.

Schließlich schließe ich einen Komponententest an, den Sie ausführen können und der die Assertionen zu diesen Ausdrücken prüft. Wenn Sie den Methodenkörper wiedergeben, werden Sie sehen, dass die relevanten Factory-Methoden an den Punkten aufgerufen werden, die ich mit dem Kommentar hervorgehoben habe Blöcke:

public class Node
{
  //initialise non-null, so we can use the MemberMemberBinding
  private NodeData _data = new NodeData();
  public NodeData Data { get { return _data; } set { _data = value; } }
  //initialise with one element so you can see how a MemberListBind
  //actually adds elements to those in a list, not creating it new.
  //Note - can't set the element to 'new Node()' as we get a Stack Overflow!
  private IList<Node> _children = new List<Node>() { null };
  public IList<Node> Children 
    { get { return _children; } set { _children = value; } }
}

public class NodeData
{
  private static int _counter = 0;
  //allows us to count the number of instances being created.
  public readonly int ID = ++_counter;
  public string Name { get; set; }
}

Da gehst du, ich denke, das sollte es abdecken.

Ob Sie sie in Ihrem Code unterstützen sollten, ist eine andere Sache! ;)




Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum