c# - Expression.Coalesce 的转换参数是做什么用的?

标签 c# clr roslyn expression-trees

有关此问题的上下文,请参阅 the documentation for the Coalesce(Expression, Expression, LambdaExpression) overload of the Expression.Coalesce Method .我指的是这个重载的第三个参数。我有几个关于它的问题,我无法在任何地方找到答案,包括微软的文档:

  • 为什么会选择使用此重载来提供转换?
  • 编译表达式时如何使用?
  • 应该如何LambdaExpression构建一个传递(我只能假设一个特定的参数签名和返回值类型是预期的)?

我反复尝试(通过将代码中使用 ?? 运算符的各种 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 并且您有代码来创建一个有效的 Coalesce 表达式树,其中包含非空 转换

关于c# - Expression.Coalesce 的转换参数是做什么用的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53588703/

相关文章:

c# - 如何在数据库中存储和访问 session

c# - .Net 处理非托管内存的方式是否不同于 C++ 运行时/二进制可执行文件?

.net - CLR内存消耗问题

c# - 如何从 EdgeJS 应用程序引用 Roslyn 程序集?

c# - Visual Studio 2015 CTP 中没有 C# 6.0?

c# - json 编码的自定义替换未按预期输出双引号

c# - 如何在 C# 中解析 .lnk

c# - 为什么检查这个 != null?

c# - 将默认的 Roslyn 项目 dll 版本从 42.42.42.42 更改为 2.0.0.0

c# - 可以通过查询结果获取结果集行数吗?