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:

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

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:

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

ou

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

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:

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

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:

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

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 :

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

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

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

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 .:

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

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:

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

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