После установки обновления 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:
логика, которая делает сравнение для перечислений (где-то в 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, а создает взаимосвязь.
Мой вопрос будет, если это предназначено? (Так как он может сломать существующий код, когда просто перекомпилирует решение)
Это выглядит довольно невинной оптимизации для меня. Я бы не ожидал, что он сломает что-либо до такой степени, что не работает: конечно, это займет другой путь через код, поэтому тесты, проверяющие, какой путь будет взят, сломаются. Однако конечный результат оценки этого выражения должен оставаться неизменным, а конечный результат перевода его на что-то еще должен привести к чему-то эквивалентному. – dasblinkenlight
Ну, код, который был взломан, делал сериализацию перечислений в SQL-запрос. Теперь это ломается, потому что он не знает, что значение, которое обрабатывается, на самом деле является перечислением. – Devedse
Возможно, у вас есть другая сборка, которая содержит эту константу, на которую ссылается ваше выражение? И вы просто не перестроили его правильно ... просто мысль. Вы уверены, что ваш enum стоит в одной сборке? –