Dan*_*nry 5 c# clr expression-trees roslyn
有关此问题的上下文,请参阅Expression.Coalesce Method 的 Coalesce(Expression, Expression, LambdaExpression) 重载的文档。我特意指的是这个重载的第三个参数。我有一些关于它的问题,但我无法在任何地方找到答案,包括微软的文档:
LambdaExpression构造一个传递(我只能假设一个特定的参数签名和预期的返回值类型)???我多次尝试(通过将代码中使用运算符的各种 lambda 函数转换为Expression<>)让 C# 编译器为我构建一个使用此参数的表达式树。但每次我使用调试器检查结果树中表达式 with 的转换参数的推论属性时,它都是.NodeType Coalescenull
我这么问是因为我正在开发一个通过分析表达式树来工作的库,我需要它来正确理解和支持这些转换。
您可以通过查看其源代码和 C# 规范来了解 C# 编译器的作用。
\n如果您查看C# 编译器中处理表达式树的合并表达式的代码,您会注意到它仅conversion在左子表达式包含用户定义的表达式时使用。
然后,您可以查看C# 规范的空合并运算符部分来查看何时发生这种情况:
\n\n\n具体
\na ?? b处理如下:\n
\n- 如果
\nA存在并且不是可为 null 的类型或引用类型,则会发生编译时错误。- [\xe2\x80\xa6]
\n- 否则,如果
\nb有一个类型并且存在从到 的B隐式转换,则结果类型为。在运行时,首先评估。如果不为 null,则解包为 type (如果存在且可为空)并转换为 type ,这将成为结果。否则,进行评估并成为结果。aBBaaaA0ABb- [\xe2\x80\xa6]
\n
因此,我们需要A具有隐式用户定义转换的类型B,并在空合并表达式中使用这两种类型:
class A\n{\n public static implicit operator B(A s) => null;\n}\n\nclass B {}\n\n\xe2\x80\xa6\n\nExpression<Func<B>> e = () => new A() ?? new B();\nRun Code Online (Sandbox Code Playgroud)\n如果你反编译这段代码,你会看到:
\nNewExpression left = Expression.New(typeof(A));\nNewExpression right = Expression.New(typeof(B));\nParameterExpression parameterExpression = Expression.Parameter(typeof(A), "p");\nUnaryExpression body = Expression.Convert(\n parameterExpression, typeof(B),\n (MethodInfo)MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/));\nParameterExpression[] obj = new ParameterExpression[1];\nobj[0] = parameterExpression;\nExpression.Lambda<Func<B>>(\n Expression.Coalesce(left, right, Expression.Lambda(body, obj)), Array.Empty<ParameterExpression>());\nRun Code Online (Sandbox Code Playgroud)\n替换GetMethodFromHandle为反射代码来获取A.op_Implicit,并且您有代码来创建Coalesce具有非 null 的有效表达式树Conversion。