Expressions cassant le code lors de la compilation avec VS2015 Update 1

.net .net-4.6 c# expression-trees visual-studio-2015

Question

Après avoir installé Visual Studio 2015 Update 1 sur ma machine, j'ai constaté l'échec de certains de mes tests unitaires. Après des recherches, j'ai pu réduire le problème à cette ligne de code:

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

Lors du survol de la variable d'expression, les résultats étaient différents dans les versions de Visual Studio:

VS 2015: VS 2015

VS 2015 Update 1: VS 2015 Update 1

La logique qui faisait la comparaison pour les enums (quelque part dans le code ServiceStack.OrmLite) agissait maintenant différemment, ce qui finissait par aboutir à ce que l'énum ne soit pas reconnu comme une énumération, ce qui aboutissait au test unitaire défaillant.

J'ai pu reproduire le problème en utilisant le code suivant:

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
}

Sur VS 2015, il ira dans le chemin d'accès UnaryExpression, et dans VS 2015 Update 1, il entrera dans le chemin ConstantExpression.

Si vous compilez la solution sur VS 2015 puis copiez le fichier .exe compilé sur un système VS 2015 Update 1, il fonctionnera de la même manière que la version VS 2015 (donc également le chemin UnaryExpression). Cela suggère qu'il n'est pas lié à JIT, mais plutôt lié à la construction.

Ma question serait si cela est prévu? (Puisqu'il pourrait casser le code existant lors d'une simple recompilation de la solution)

Réponse acceptée

Cela semble être quelque chose qui a été cassé avec le RTM VS2015. Si vous le compilez sans l'ancienne version de Roslyn, il s'agit en fait d'une ConstantExpression .

Compilateur 4.5: https://dotnetfiddle.net/XpKg10
Compilateur Roslyn: https://dotnetfiddle.net/zeGVdh




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi