2015-12-05 3 views
21

После установки обновления Visual Studio 2015 Update 1 на моей машине я увидел, что некоторые из моих модульных тестов не удались. После выполнения некоторого исследования мне удалось свести задачу к этой строке кода:Выражения, разбивающие код при компиляции с использованием VS2015 Update 1

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

При наведении на переменную выражения результаты были различными в версиях Visual Studio:

VS 2015: VS 2015

VS 2015 Update 1: VS 2015 Update 1

логика, которая делает сравнение для перечислений (где-то в ServiceStack.O rmLite) теперь действовали по-разному, что в конечном итоге приводило к тому, что перечисление не было признано в качестве перечисления, что привело к неудачному модульному тесту.

Я был в состоянии воспроизвести проблему, используя следующий код:

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 
} 

В VS 2015 будет идти в путь УнарноеВыражение, и в VS 2015 Update 1 будет идти в путь ConstantExpression.

Если вы скомпилируете решение на VS 2015, а затем скопируете скомпилированный файл .exe в систему VS 2015 Update 1, он будет работать так же, как версия VS 2015 (так же путь UnaryExpression). Это говорит о том, что он не связан с JIT, а создает взаимосвязь.

Мой вопрос будет, если это предназначено? (Так как он может сломать существующий код, когда просто перекомпилирует решение)

+2

Это выглядит довольно невинной оптимизации для меня. Я бы не ожидал, что он сломает что-либо до такой степени, что не работает: конечно, это займет другой путь через код, поэтому тесты, проверяющие, какой путь будет взят, сломаются. Однако конечный результат оценки этого выражения должен оставаться неизменным, а конечный результат перевода его на что-то еще должен привести к чему-то эквивалентному. – dasblinkenlight

+1

Ну, код, который был взломан, делал сериализацию перечислений в SQL-запрос. Теперь это ломается, потому что он не знает, что значение, которое обрабатывается, на самом деле является перечислением. – Devedse

+0

Возможно, у вас есть другая сборка, которая содержит эту константу, на которую ссылается ваше выражение? И вы просто не перестроили его правильно ... просто мысль. Вы уверены, что ваш enum стоит в одной сборке? –

ответ

2

Это похоже на то, что было фактически нарушено RTM VS2015. Если вы скомпилируете его без старой версии Roslyn, это на самом деле ConstantExpression.

4,5 составитель: https://dotnetfiddle.net/XpKg10
Рослин Компилятор: https://dotnetfiddle.net/zeGVdh

 Смежные вопросы

  • Нет связанных вопросов^_^