代码之家  ›  专栏  ›  技术社区  ›  bolov

linq表达式<TDelegate>赋值在语言语法级别上是如何工作的

  •  3
  • bolov  · 技术社区  · 7 年前

    TLDR:这是如何编译的?

    class A{};
    Expression<Func<A, int>> e = x => 24; // I don't understant what makes this compile
                                          // and what happens at this assignment
    

    最低限度是多少 class E E e = x => 24;


    一些调查

    class E {};
    
    E e = x => 24;
    

    int delegate MyHandle();
    

    我没有找到任何办法 class

    此外,我还查看了 Expression -> LambdaExpression -> Expression<TDelegate> Expression<TDelegate>

    我更努力创造属于自己的 E类 模仿

    // basically a copy-paste of the metadata of `Expression<TDelegate>`
    public sealed class E<TDelegate> : LambdaExpression
    {
    
        public TDelegate Compile() => default(TDelegate);
        public TDelegate Compile(DebugInfoGenerator debugInfoGenerator) => default(TDelegate);
        public TDelegate Compile(bool preferInterpretation) => default(TDelegate);
        public Expression Update(Expression body, IEnumerable<ParameterExpression> parameters)
            => default(Expression);
        protected override Expression Accept(ExpressionVisitor visitor) => null;
    }
    


    我刚开始使用Moq,因为我不能想当然地去理解它是如何工作的/它是如何实现的。这是一系列调查的第一部分。

    我现在特别想弄明白

    public class A
    {
        public virtual int Foo() => throw new NotImplementedException();
        public virtual int Bar() => throw new NotImplementedException();
    }
    
    var a = new Mock<A>();
    
    a.Setup(x => x.Foo()).Returns(24); // ??
    Console.WriteLine(a.Object.Foo());
    

    a 通过那个兰巴?据我所知,lambda只是一个可调用的对象,但不知怎么的神奇 知道lambda的真实身体,也就是说,如果你通过,它会扔 x => 24 x => x.Foo() + x.Bar() 但我会接受的 x => x.Foo()

    我看到了 Setup 参数的类型为 Expression<Func<A, int>> 因此我现在的问题。

    2 回复  |  直到 7 年前
        1
  •  4
  •   Ben Voigt    7 年前

    C规范对 System.Linq.Expressions.Expression<D> ; 对于你自己的类型,你不能得到同样的待遇。

    表达式树允许lambda表达式表示为数据结构,而不是可执行代码。表达式树是窗体的表达式树类型的值 System.Linq.Expressions.Expression<D> ,在哪里 D 是任何委托类型。

    资料来源: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/types#expression-tree-types

        2
  •  0
  •   Harald Coppoolse    7 年前

    这是一个Lambda表达式:

    x => 24
    

    MSDN Lambda expressions lambda表达式可用于创建 或者一个 .

    A Func<T, int> x => 是函数的输出:

    Func<string, int> func = x => x.Length;
    

    这里x应该是一个字符串,在 => 可以使用,但没有义务使用这个x来产生必须是int的输出。

    Func<int, int> func = x => x = -x;
    

    这里x应该是一个int。函数的返回值是-x,它也是一个int。

    Expression 24 . 其他表达式可能是加法,它将两个表达式作为输入,并具有一个输出值。其他表达式有乘法、求反等,它们返回一个“数”,或者像AND或NOR等布尔表达式,它们返回一个布尔值。

    一种特殊的表达式(即派生类)是 LambdaExpression . A 通常表示类似于对象的函数:它有零个或多个输入参数和一个输出参数。将值赋给 使用lambda表达式(注意lambda表达式中的空格!):

    Expression<Func<string, int>> myExpression = x => x.Length;
    

    我之前写了lambda表达式 x => x.Length System.Linq.Expressions.Expression<TDelegate> ,属于 LambdaExpression ,因此可以将其分配给 Expression<Func<string, int>>

    你的问题是:

    E e = x => 24 ?

    您的类E将需要一个接受 System.Linq.Expressions.Expression<Func<MyClass, int> 从你的lambda表情 MyClass 可以是 object

    表达式 . 但是,如果你这样做,你将无法使用任何 Expression<Func<MyClass, int>

    关于你的模拟代码

    显然,您有一个具有两个函数Foo和Bar的类a,并且您希望实例化一个Mock对象来模拟a的功能。

    var myAmock = new Mock<A>();
    myAmock.Setup(x => x.Foo()).Returns(24);
    

    这个说,那个说 myAmock A . 每当有人打电话给 Foo