gpt4 book ai didi

c# - MemberBinding LINQ 表达式有哪些示例?

转载 作者:可可西里 更新时间:2023-11-01 08:03:21 26 4
gpt4 key购买 nike

有三种可能,但我找不到例子:

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

我想写一些单元测试,看看我能不能处理它们,但我不知道怎么写,除了第一个,它似乎是 new Foo { Property = "value"} 其中 Property = "value"MemberAssignment 类型的表达式。

另见 MSDN article .

最佳答案

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

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# 编译器生成表达式,以便您通过执行以下操作来研究它们的工作原理:

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

将生成一个内联表达式,其中包含对 Expression.New 的调用,传递 Node 类型的 ConstructorInfo。在 Reflector 中打开输出 DLL,看看我的意思。

我应该首先提到,您询问的这三种表达式类型通常在 Expression.New 中的 MemberBinding[] 数组中传递,或者相互嵌入(因为成员初始值设定项本质上是递归的)。

关于情节......

成员分配

MemberAssignment 表达式表示具有给定表达式返回值的新实例的单个成员的设置。它是使用 Expression.Bind 工厂方法在代码中生成的。这是您将看到的最常见的情况,在 C# 代码中,这等同于以下内容:

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

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

成员成员绑定(bind)

MemberMemberBinding 表示已经初始化的成员的成员的内联初始化(即新成员,或者无论如何都不能为 null 的结构)。它是通过 Expression.MemberBind 创建的,不代表创建新实例。因此,它与 MemberBind 方法的不同之处在于,它不采用 ConstructorInfo,而是采用对 Property Get 方法(属性访问器)的引用。因此,尝试以这种方式初始化从 null 开始的成员将导致 NullReferenceException。

因此,要在代码中生成它,您可以这样做:

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

这可能看起来有点奇怪,但这里发生的是正在执行 Data 的属性 get 方法以获取对已初始化成员的引用。有了它,内部的 MemberBindings 就会依次执行,所以上面的代码实际上并没有覆盖数据,而是这样做:

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

这就是为什么需要这种表达式类型的原因,因为如果你必须设置多个属性值,你不能在一行中完成它,除非有一些特殊的表达式/语法来完成它。如果 NodeData 有另一个字符串成员 (OtherName),您也想同时设置它,没有初始化语法/表达式,您必须这样做:

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

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

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

Data = 位是 MemberMemberBinding。

我希望这很清楚!

成员列表绑定(bind)

Expression.ListBind 方法创建(还需要调用 Expression.ElementInit),这类似于 MemberMemberBinding(对象的成员是 不是被重新创建),但这一次,它是一个 ICollection/IList 的实例,它被添加到 带有内联元素.:

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

因此,最后两个表达式有点边缘情况,但肯定是您很可能会遇到的事情,因为它们显然非常有用。

最后,我附上了一个您可以运行的单元测试,它将证明我对这些表达式所做的断言 - 如果您反射(reflect)方法主体,您会看到相关的工厂方法在我强调的点被调用带有评论 block :

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

好了,我认为应该涵盖它。

您是否应该在您的代码中支持它们是另一回事! ;)

关于c# - MemberBinding LINQ 表达式有哪些示例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2917448/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com