Why are generic and non-generic structs treated differently when building expression that lifts operator == to nullable?

只谈情不闲聊 提交于 2019-11-30 10:55:00

The short answer is: yes, that's a bug. I've put a minimal repro and a short analysis below.

My apologies. I wrote a lot of that code and so it was likely my bad.

I have sent a repro off to the Roslyn development, test and program management teams. I doubt this reproduces in Roslyn, but they'll verify that it does not and decide whether this makes the bar for a C# 5 service pack.

Feel free to enter an issue on connect.microsoft.com as well if you want it tracked there as well.


Minimal repro:

using System;
using System.Linq.Expressions;
struct S<T>
{
    public static bool operator ==(S<T> a, S<T> b) { return false; }
    public static bool operator !=(S<T> a, S<T> b) { return false; }
}
class Program
{
    static void Main()
    {
        Expression<Func<S<int>?, S<int>, bool>> x = (a, b) => a == b;
    }
}

The code that is generated in the minimal repro is equivalent to

ParameterExpression pa = Expression.Parameter(typeof(S<int>?), "a");
ParameterExpression pb = Expression.Parameter(typeof(S<int>), "b");
Expression.Lambda<Func<S<int>?, S<int>, bool>>(
    Expression.Equal(pa, pb, false, infoof(S<int>.op_Equality)
    new ParameterExpression[2] { pa, pb } );

Where infoof is a fake operator that gets a MethodInfo for the given method.

The correct code would be:

ParameterExpression pa = Expression.Parameter(typeof(S<int>?), "a");
ParameterExpression pb = Expression.Parameter(typeof(S<int>), "b");
Expression.Lambda<Func<S<int>?, S<int>, bool>>(
    Expression.Equal(pa, Expression.Convert(pb, typeof(S<int>?), false, infoof(S<int>.op_Equality)
    new ParameterExpression[2] { pa, pb } );

The Equal method cannot deal with one nullable, one non-nullable operands. It requires that either both are nullable or neither is.

(Note that the false is correct. This Boolean controls whether the result of a lifted equality is a lifted Boolean; in C# it is not, in VB it is.)

Yes, this bug is gone in Roslyn (the compiler under development). We'll see about the existing product.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!