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;
Visual Studio错误是“无法将lambda表达式转换为类型'E',因为它不是委托类型”,这令人困惑,因为据我所知,委托是这样声明的:
int delegate MyHandle();
我没有找到任何使class
成为代表的方法。
此外,我查看了Expression -> LambdaExpression -> Expression<TDelegate>
的元数据,但无法确定是什么语法/声明使Expression<TDelegate>
充当了委托人。
甚至我还尝试创建自己的class E
来模仿Expression<TDelegate>
,但我什至无法编译该类
// 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;
}
出现错误“'LambdaExpression'不包含带有0个参数的构造函数”
上下文(可以跳过):
我开始使用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());
我正在尝试了解信息“方法Foo”如何传递给a
通过那个lambda?据我所知,lambda只是一个可调用的对象,但是a
以某种方式神奇地知道了lambda的实际主体,即如果您通过x => 24
或x => x.Foo() + x.Bar()
但会接受{ {1}}
我看到x => x.Foo()
参数的类型为Setup
,因此是我当前的问题。
答案 0 :(得分:4)
C#规范对System.Linq.Expressions.Expression<D>
进行了特殊处理;您无法针对自己的类型获得相同的待遇。
表达式树允许将lambda表达式表示为数据结构而不是可执行代码。表达式树是形式为
System.Linq.Expressions.Expression<D>
的表达式树类型的值,其中D
是任何委托类型。
答案 1 :(得分:0)
这是Lambda表达式:
x => 24
根据MSDN Lambda expressions,lambda表达式可用于创建委托或表达式树类型。
Func<T, int>
是一个委托函数,它以T作为输入,并返回一个int作为输出。如果将上面的lambda表达式分配给此Func,则编译器会假定lambda表达式中的x
是Func的输入,而=>
之后的部分是Func的输出:
Func<string, int> func = x => x.Length;
这里x应该是一个字符串,=>
之后的部分可以使用但不必使用,这个x产生的输出必须是int。
Func<int, int> func = x => x = -x;
这里x应该是一个整数。该函数的返回值是-x,它也是一个整数。
Expression
是各种表达式的基类。表达式表示返回值的操作。最基本的表达式是常量,它们仅表示一个常量值,例如24
。其他表达式可能是加法运算,它们将两个表达式作为输入并具有一个输出值。其他表达式是返回“数字”的乘法,否定等,或返回布尔值的布尔表达式(例如AND或NOR等)。
一种特殊的表达式(因此是派生类)是LambdaExpression
。 LambdaExpression
通常表示类似函数的对象:它具有零个或多个输入参数和一个输出参数。您可以使用lambda表达式为LambdaExpression
分配一个值(请注意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类是什么?
您的E类将需要一个接受System.Linq.Expressions.Expression<Func<MyClass, int>
作为参数的构造函数(或赋值运算符)。如果您不使用Lambda表达式中的x
,则MyClass
可以是object
当然,如果构造函数采用任何基类,例如Expression
,也可以接受。但是,如果这样做,将无法使用任何Expression<Func<MyClass, int>
功能。
关于您的模拟代码
显然,您有一个具有两个函数Foo和Bar的A类,并且您想实例化一个Mock对象来模拟A的功能。
var myAmock = new Mock<A>();
myAmock.Setup(x => x.Foo()).Returns(24);
这表示myAmock
是一个应该模拟类A
的行为的对象。每当有人调用Foo
函数时,它应该返回值24。