Expression.Coalesce的转换参数是做什么用的?
What is the conversion parameter of Expression.Coalesce for?
有关此问题的上下文,请参阅 the documentation for the Coalesce(Expression, Expression, LambdaExpression) overload of the Expression.Coalesce Method。我指的是这个重载的第三个参数。我有几个关于它的问题,我一直无法在任何地方找到答案,包括微软的文档:
- 为什么会选择使用此重载来提供转换?
- 编译表达式时如何使用?
- 应该如何构建
LambdaExpression
one passes(我只能假设一个特定的参数签名和return值类型将是预期的)?
我反复尝试(通过将代码中使用 ??
运算符的各种 lambda 函数转换为 Expression<>
)让 C# 编译器为我编写一个表达式树,它利用了这个范围。但是每次我使用调试器检查 the corollary property of the conversion parameter 在结果树中使用 NodeType
Coalesce
的表达式时,它是 null
.
我问是因为我正在开发一个通过分析表达式树工作的库,我需要它来正确理解和支持这些转换。
您可以通过查看其源代码和 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 以了解何时发生:
Specifically, a ?? b
is processed as follows:
- If
A
exists and is not a nullable type or a reference type, a compile-time error occurs.
- […]
- Otherwise, if
b
has a type B
and an implicit conversion exists from a
to B
, the result type is B
. At run-time, a
is first evaluated. If a
is not null, a
is unwrapped to type A0
(if A
exists and is nullable) and converted to type B
, and this becomes the result. Otherwise, b
is evaluated and becomes the result.
- […]
所以我们需要类型 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
并且您有代码创建具有非空 Conversion
.[=37= 的有效 Coalesce
表达式树]
有关此问题的上下文,请参阅 the documentation for the Coalesce(Expression, Expression, LambdaExpression) overload of the Expression.Coalesce Method。我指的是这个重载的第三个参数。我有几个关于它的问题,我一直无法在任何地方找到答案,包括微软的文档:
- 为什么会选择使用此重载来提供转换?
- 编译表达式时如何使用?
- 应该如何构建
LambdaExpression
one passes(我只能假设一个特定的参数签名和return值类型将是预期的)?
我反复尝试(通过将代码中使用 ??
运算符的各种 lambda 函数转换为 Expression<>
)让 C# 编译器为我编写一个表达式树,它利用了这个范围。但是每次我使用调试器检查 the corollary property of the conversion parameter 在结果树中使用 NodeType
Coalesce
的表达式时,它是 null
.
我问是因为我正在开发一个通过分析表达式树工作的库,我需要它来正确理解和支持这些转换。
您可以通过查看其源代码和 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 以了解何时发生:
Specifically,
a ?? b
is processed as follows:
- If
A
exists and is not a nullable type or a reference type, a compile-time error occurs.- […]
- Otherwise, if
b
has a typeB
and an implicit conversion exists froma
toB
, the result type isB
. At run-time,a
is first evaluated. Ifa
is not null,a
is unwrapped to typeA0
(ifA
exists and is nullable) and converted to typeB
, and this becomes the result. Otherwise,b
is evaluated and becomes the result.- […]
所以我们需要类型 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
并且您有代码创建具有非空 Conversion
.[=37= 的有效 Coalesce
表达式树]