什么是MemberBinding LINQ EX pressions一些例子吗? [英] What are some examples of MemberBinding LINQ expressions?

查看:206
本文介绍了什么是MemberBinding LINQ EX pressions一些例子吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有三种可能性,但我无法找到例子:

There are three possibilities, but I can't find examples:

  1. System.Linq.Ex pressions.MemberAssignment
  2. System.Linq.Ex pressions.MemberListBinding
  3. System.Linq.Ex pressions.MemberMemberBinding

我想写一些单元测试,看看我是否能够处理它们,但我不知道如何,除了第一个,这似乎是把它们写新富{属性=值} ,其中属性=值是一个类型的前pression MemberAssignment

I want to write some unit tests to see if I can handle them, but I don't know how to write them except for the first one, which seems to be new Foo { Property = "value" } where Property = "value" is an expression of type MemberAssignment.

另请参阅此 MSDN文章

推荐答案

修改这将替换响应第一条评论的previous答案。

EDIT This replaces the previous answer in response to the first comment.

在我使用的这些例子中的类如下:

The classes I'm using in these examples are as follows:

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

首先,你可以得到C#编译器生成EX pressions为您调查他们是如何做的工作更多的以下内容:

Firstly, you can get the C# compiler to generate expressions for you to investigate how they work more by doing the following:

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

会生成一个包含调用防爆pression.New ,传递的节点类型的ConstructorInfo内联前pression。打开在反射器输出的DLL明白我的意思。

Will generate an inline expression that contains a call to Expression.New, passing the ConstructorInfo of the Node type. Open the output DLL in Reflector to see what I mean.

我首先要提到你问一般是通过在MemberBinding []数组中的前pression.New,或嵌入在这三个EX pression类型对方(因为成员初始化本质上是递归)。

I should first mention that these three expression types you ask about are typically passed in a MemberBinding[] array in an Expression.New, or embedded within each other (since Member initializers are inherently recursive).

在对剧情...

在MemberAssignment EX pression重新presents在设置一个新的实例与给定EX $ P $的返回值的单个成员pssion。它使用了防爆pression.Bind 工厂方法产生于code。这是最常见的,你会看到,在C#code这等同于以下内容:

The MemberAssignment expression represents the setting of a single member of a new instance with the return value of a given expression. It is produced in code using the Expression.Bind factory method. This is the most common that you'll see, and in C# code this is equivalent to the following:

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

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

MemberMemberBinding

在MemberMemberBinding重新presents一个已经初始化的成员成员的内联初始化(即newed,还是结构不能为空反正)。它是通过防爆pression.MemberBind 不重新present创建一个新的实例的。因此,它不同于MemberBind方法不采取一个ConstructorInfo,而是引用属性Get方法(属性访问器)。其结果是,如果试图在这种方式启动关闭null将会导致一个NullReferenceException初始化一个部件

MemberMemberBinding

The MemberMemberBinding represents the inline initialisation of the members of a member that is already initialised (i.e. newed, or a struct that can't be null anyway). It is created through the Expression.MemberBind and does not represent creating a new instance. Therefore, it differs from the MemberBind method by not taking a ConstructorInfo, but a reference to a Property Get method (property accessor). As a result, an attempt to initialise a member in this way that starts off null will result in a NullReferenceException.

于是,产生这code你这样做:

So, to generate this in code you do this:

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

这似乎有点古怪,但这里发生了什么是正在执行的属性get方法数据来获得一个参考已经初始化成员。随着在手,内MemberBindings然后依次执行,所以有效地上面code不是覆盖数据,但这样做的:

This might seem a bit odd, but what's happening here is that the property get method for Data is being executed to obtain a reference to the already initialised member. With that in hand, the inner MemberBindings are then executed in turn, so effectively the above code is not overwriting Data, but doing this:

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

这就是为什么这个前pression类型是必需的,因为如果你要设置多个属性值,你不能做一个一行程序,除非有一些特殊的EX pression /语法来做到这一点。如果 NODEDATA 还有另外一个字符串成员(中文别名),您也想设置的同时,无需初始化器语法/ EX pressions,你必须做到这一点:

And this is why this expression type is required, because if you've got to set multiple property values, you can't do it in a one-liner, unless there's some special expression/syntax to do it. If NodeData had another string member (OtherName) that you also wanted to set at the same time, without initialiser syntax/expressions, you'd have to do this:

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

这是不是一个班轮 - 但这是:

Which isn't a one liner - but this is:

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

数据= 位是MemberMemberBinding。

Where the Data = bit is the MemberMemberBinding.

我希望这是明确的!

创建了防爆pression.ListBind 方法(也需要调用防爆pression.ElementInit ),这类似于MemberMemberBinding(该对象的成员的没有被重新创建),但是这一次,它的ICollection / IList的实例,它是是的添加到与内联元素:

Created by the Expression.ListBind method (requiring also calls to Expression.ElementInit), this is similar to the MemberMemberBinding (in that an object's member is not being created anew), but this time, it's an instance of ICollection/IList that is being added to with inline elements.:

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

所以,最后这两个前pressions都有点边沿的情况下,但可以肯定的事情,你很可能会遇到,因为他们显然是非常有用的。

So, these last two expressions are kinda edge-cases, but certainly are things that you could well come across, as they are clearly very useful.

最后,我附上一个单元测试,您可以运行,这将证明我做这些EX pressions断言 - 如果你反映的方法体中,你会看到相关的工厂方法被称为在点我想强调的注释块:

Finally, I enclose a unit test that you can run that will prove the assertions I make about these expressions - and if you reflect the method body, you'll see that the relevant factory methods are being called at the points I highlight with the comment blocks:

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

你去那里,我认为应该覆盖它。

There you go, I think that should cover it.

是否应该支持他们在code是另一回事! ;)

Whether you should be supporting them in your code is another matter! ;)

这篇关于什么是MemberBinding LINQ EX pressions一些例子吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆