Quels sont quelques exemples d'expressions LINQ MemberBinding?

.net c# expression-trees linq

Question

Il y a trois possibilités, mais je ne trouve pas d'exemples:

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

Je veux écrire des tests unitaires pour voir si je peux les gérer, mais je ne sais pas comment les écrire, sauf pour le premier, qui semble être new Foo { Property = "value" } where Property = "value" est une expression de type MemberAssignment .

Voir aussi cet article MSDN .

Réponse acceptée

EDIT Ceci remplace la réponse précédente en réponse au premier commentaire.

Les classes que j'utilise dans ces exemples sont les suivantes:

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; }
}

Tout d'abord, vous pouvez faire en sorte que le compilateur C # génère des expressions afin que vous puissiez en savoir plus sur leur fonctionnement en procédant comme suit:

Expression<Func<Node>> = () => new Node();

Générera une expression en ligne contenant un appel à Expression.New , en passant le ConstructorInfo du type Node. Ouvrez la DLL de sortie dans Reflector pour voir ce que je veux dire.

Je dois d’abord mentionner que ces trois types d’expression que vous demandez sont généralement passés dans un tableau MemberBinding [] dans un Expression.New, ou sont imbriqués les uns dans les autres (car les initialiseurs de membre sont intrinsèquement récursifs).

Sur la parcelle ...

MembreAssignation

L'expression MemberAssignment représente la définition d'un seul membre d'une nouvelle instance avec la valeur de retour d'une expression donnée. Il est produit en code à l'aide de la méthode de fabrique Expression.Bind . C’est le plus courant que vous verrez. En code C #, cela équivaut à ce qui suit:

new NodeData() { /* start */ Name = "hello" /* end */ };

ou

new Node() { /* start */ Data = new NodeData() /* end */ };

MemberMemberBinding

MemberMemberBinding représente l'initialisation en ligne des membres d'un membre déjà initialisé (c'est-à-dire newed ou une structure qui ne peut pas être nulle de toute façon). Il est créé via Expression.MemberBind et ne représente pas la création d'une nouvelle instance . Par conséquent, elle diffère de la méthode MemberBind en ne prenant pas un ConstructorInfo, mais une référence à une méthode Property Get (accesseur de propriété). Par conséquent, une tentative d'initialisation d'un membre de cette manière qui démarre null entraîne une exception NullReferenceException.

Donc, pour générer ceci dans le code, procédez comme suit:

new Node() { /* start */ Data = { Name = "hello world" } /* end */};

Cela peut sembler un peu étrange, mais ce qui se passe ici, c'est que la méthode property get pour Data est en cours d'exécution pour obtenir une référence au membre déjà initialisé. Avec cela en main, les MemberBindings internes sont ensuite exécutés à tour de rôle. Ainsi, le code ci-dessus n’écrase pas Data, mais le fait:

new Node().Data.Name = "hello world";

Et c’est la raison pour laquelle ce type d’expression est requis, car si vous devez définir plusieurs valeurs de propriété, vous ne pouvez pas le faire dans une ligne, à moins qu’il n’existe une syntaxe / expression particulière pour le faire. Si NodeData a un autre membre de chaîne ( OtherName ) que vous souhaitez également définir en même temps, sans syntaxe / expressions d'initialiseur, vous devez procéder comme OtherName :

var node = new Node();
node.Data.Name = "first";
node.Data.OtherName = "second";

Ce qui n'est pas un one-liner - mais c'est:

var node = new Node() { Data = { Name = "first", OtherName="second" } };

Où le Data = bit est le MemberMemberBinding.

J'espère que c'est clair!

MemberListBinding

Créée par la méthode Expression.ListBind (nécessitant également des appels à Expression.ElementInit ), elle est similaire à MemberMemberBinding (en ce sens que le membre d'un objet n'est pas créé à nouveau), mais cette fois, il s'agit d'une instance de ICollection / IList ajouté à avec des éléments en ligne .:

new Node() { /* start */ Children = { new Node(), new Node() } /* end */ };

Donc, ces deux dernières expressions sont un peu des cas extrêmes, mais sont certainement des choses que vous pourriez bien rencontrer car elles sont clairement très utiles.

Enfin, je joins un test unitaire que vous pouvez exécuter et qui prouvera les assertions que je fais à propos de ces expressions - et si vous reflétez le corps de la méthode, vous verrez que les méthodes d'usine correspondantes sont appelées aux points que je soulève avec le commentaire. blocs:

[TestMethod]
public void TestMethod1()
{
  Expression<Func<Node>> e = 
    () => new Node() { Data = new NodeData() };

  Expression<Func<Node>> e2 = 
    () => new Node() { Data = { Name = "MemberMemberBinding" } };

  Expression<Func<Node>> e3 = 
    () => new Node() { Children = { new Node(), new Node() } };

  var f = e.Compile();
  var f2 = e2.Compile();
  var f3 = e3.Compile();

  var node = f();
  //proves that this data was created anew as part of the expression.
  Assert.AreEqual(2, node.Data.ID);
  var node2 = f2();
  //proves that the data node's name was merely initialised, and that the
  //node data itself was not created anew within the expression.
  Assert.AreEqual(3, node2.Data.ID);
  Assert.AreEqual("MemberMemberBinding", node2.Data.Name);
  var node3 = f3();
  //count is three because the two elements in the MemberListBinding
  //merely added two to the existing first null item.
  Assert.AreEqual(3, node3.Children.Count);
}

Voilà, je pense que cela devrait couvrir.

Que vous deviez les supporter dans votre code est une autre affaire! ;)



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi