有关此问题的上下文,请参见the documentation for the Coalesce(Expression, Expression, LambdaExpression) overload of the Expression.Coalesce Method。我专门指的是此重载的第三个参数。我对此有一些疑问,无法在任何地方找到答案,包括Microsoft的文档:
LambdaExpression
一遍(我只能假设特定的参数签名,并且期望返回值类型)?我已经反复尝试(通过将使用代码中的??
运算符的各种lambda函数转换为Expression<>
)来使C#编译器为我编写一个使用此参数的表达式树。但是每次我使用调试器在结果树中检查the corollary property of the conversion parameter中带有NodeType
Coalesce
的表达式时,它就是null
。
之所以问,是因为我正在研究一个通过分析表达式树而工作的库,因此我需要它来正确理解和支持这些转换。
答案 0 :(得分:2)
您可以通过查看源代码和C#规范来弄清楚C#编译器的作用。
如果您查看the code in the C# compiler that handles the coalesce expression for expression trees,则会注意到它仅在左侧子表达式包含用户定义的表达式时才使用conversion
。
然后您可以查看at the section The null coalescing operator of the C# spec看看何时发生:
具体来说,
a ?? b
的处理如下:
- 如果
A
存在并且不是可为空的类型或引用类型,则将发生编译时错误。- […]
- 否则,如果
b
具有类型B
,并且存在从a
到B
的隐式转换,则结果类型为B
。在运行时,首先评估a
。如果a
不为空,则将a
展开为类型A0
(如果A
存在并且可以为空)并转换为类型B
,则它变为结果。否则,将评估b
并成为结果。- […]
因此,我们需要类型A
,该类型具有用户定义的向B
的隐式转换,并在空合并表达式中使用这两种类型:
class A
{
public static implicit operator B(A s) => null;
}
class B {}
…
Expression<Func<B>> e = () => new A() ?? new B();
如果您decompile this code, you'll see:
NewExpression left = Expression.New(typeof(A));
NewExpression right = Expression.New(typeof(B));
ParameterExpression parameterExpression = Expression.Parameter(typeof(A), "p");
UnaryExpression body = Expression.Convert(
parameterExpression, typeof(B),
(MethodInfo)MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/));
ParameterExpression[] obj = new ParameterExpression[1];
obj[0] = parameterExpression;
Expression.Lambda<Func<B>>(
Expression.Coalesce(left, right, Expression.Lambda(body, obj)), Array.Empty<ParameterExpression>());
用反射代码替换GetMethodFromHandle
以获得A.op_Implicit
,并且您具有使用非空Coalesce
创建有效的Conversion
表达式树的代码。