简体   繁体   English

使用VS2015 Update 1编译时表达式破坏代码

[英]Expressions breaking code when compiled using VS2015 Update 1

After installing Visual Studio 2015 Update 1 on my machine I saw that some of my unit tests failed. 在我的机器上安装Visual Studio 2015 Update 1之后,我看到我的一些单元测试失败了。 After doing some investigation I was able to reduce the problem to this line of code: 在做了一些调查后,我能够将问题减少到这行代码:

Expression<Func<GameObject, bool>> expression = t => t.X == 0 && t.Y == 0 && t.GameObjectType == GameObjectType.WindMill;

When hovering over the expression variable the results were different in the versions of Visual Studio: 将鼠标悬停在表达式变量上时,Visual Studio版本中的结果会有所不同:

VS 2015: VS 2015: VS 2015

VS 2015 Update 1: VS 2015 Update 1: VS 2015 Update 1

The logic that was doing the comparison for the enums (somewhere in ServiceStack.OrmLite code) now acted differently which then eventually resulted in the enum not being recognized as an enum, resulting in the failing unit test. 正在对枚举进行比较的逻辑(ServiceStack.OrmLite代码中的某个地方)现在采取了不同的行为,最终导致枚举不被识别为枚举,从而导致单元测试失败。

I was able to reproduce the problem using the following code: 我能够使用以下代码重现该问题:

class Program
{
    static void Main(string[] args)
    {
        var gameObjects = new List<GameObject> {
            new GameObject { X = 0, Y = 0, GameObjectType = GameObjectType.WindMill },
            new GameObject { X = 0, Y = 1, GameObjectType = GameObjectType.Pipe },
            new GameObject { X = 0, Y = 2, GameObjectType = GameObjectType.Factory }
        };

        var gameObjectsQueryable = gameObjects.AsQueryable();

        Expression<Func<GameObject, bool>> expression = t => t.X == 0 && t.Y == 0 && t.GameObjectType == GameObjectType.WindMill;

        var result = gameObjectsQueryable.Where(expression);

        var resultAsList = result.ToList();

        foreach (var item in resultAsList)
        {
            Console.WriteLine(item);
        }

        //Obtain the t.GameObjectType == GameObjectType.WindMill part
        var binaryExpression = expression.Body as BinaryExpression;
        var right = binaryExpression.Right;
        var binaryExpression2 = right as BinaryExpression;
        var right2 = binaryExpression2.Right;

        if (right2 is UnaryExpression)
        {
            Console.WriteLine("Found UnaryExpression (This happens when the solution is build with VS2015)...");

            var right2Unary = binaryExpression2.Right as UnaryExpression;
            var right2Constant = right2Unary.Operand as ConstantExpression;
            CheckIfConsantIsAsExpected(right2Constant);
        }
        else
        {
            Console.WriteLine("Found ConstantExpression (This happens when the solution is build with VS2015 Update 1)...");

            var right2Constant = binaryExpression2.Right as ConstantExpression;
            CheckIfConsantIsAsExpected(right2Constant);
        }

        Console.ReadKey();
    }

    public static void CheckIfConsantIsAsExpected(ConstantExpression expression)
    {
        if (expression.Value.Equals(GameObjectType.WindMill))
        {
            Console.WriteLine($"The value is the enum we expected :), : {expression.Value}");
        }
        else
        {
            Console.WriteLine($"The value is not the enum we expected :(, : {expression.Value}");
        }
    }
}

public class GameObject
{
    public int X { get; set; }
    public int Y { get; set; }
    public GameObjectType GameObjectType { get; set; }

    public override string ToString()
    {
        return $"{X},{Y}: {GameObjectType}";
    }
}

public enum GameObjectType
{
    WindMill = 100,
    Pipe = 200,
    Factory = 300
}

On VS 2015 it will go into the UnaryExpression path, and in VS 2015 Update 1 it will go into the ConstantExpression path. 在VS 2015上,它将进入UnaryExpression路径,在VS 2015 Update 1中,它将进入ConstantExpression路径。

If you compile the solution on VS 2015 and then copy the compiled .exe file to a VS 2015 Update 1 system it will run the same as the VS 2015 version (So also the UnaryExpression path). 如果您在VS 2015上编译解决方案然后将已编译的.exe文件复制到VS 2015 Update 1系统,它将运行与VS 2015版本相同(因此也是UnaryExpression路径)。 This suggests it is not JIT related but instead build related. 这表明它不是JIT相关的,而是建立相关的。

My question would be if this is intended? 我的问题是,如果这是有意的吗? (Since it could break existing code when simply recompiling the solution) (因为它只会在重新编译解决方案时破坏现有代码)

This appears to be something that was actually broken with the RTM VS2015. 这似乎是RTM VS2015实际上已经破解的东西。 If you compile it without the old version of Roslyn it is actually a ConstantExpression . 如果你在没有旧版Roslyn的情况下编译它,它实际上是一个ConstantExpression

4.5 compiler: https://dotnetfiddle.net/XpKg10 4.5编译器: https//dotnetfiddle.net/XpKg10
Roslyn compiler: https://dotnetfiddle.net/zeGVdh Roslyn编译器: https//dotnetfiddle.net/zeGVdh

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM