使用 VS2015 Update 1 编译时表达式破坏代码
Expressions breaking code when compiled using VS2015 Update 1
在我的机器上安装 Visual Studio 2015 Update 1 后,我发现我的一些单元测试失败了。在做了一些调查之后,我能够将问题减少到这行代码:
Expression<Func<GameObject, bool>> expression = t => t.X == 0 && t.Y == 0 && t.GameObjectType == GameObjectType.WindMill;
将鼠标悬停在表达式变量上时,Visual Studio 版本的结果不同:
对比 2015 年:
VS 2015 更新 1:
对枚举进行比较的逻辑(ServiceStack.OrmLite 代码中的某处)现在的行为有所不同,最终导致枚举未被识别为枚举,从而导致单元测试失败。
我能够使用以下代码重现该问题:
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 中它将进入 UnaryExpression 路径,在 VS 2015 Update 1 中它将进入 ConstantExpression 路径。
如果您在 VS 2015 上编译解决方案,然后将编译后的 .exe 文件复制到 VS 2015 Update 1 系统,它将 运行 与 VS 2015 版本相同(UnaryExpression 路径也是如此)。这表明它与 JIT 无关,而是与构建相关。
我的问题是这是否是故意的? (因为它可能会在简单地重新编译解决方案时破坏现有代码)
这似乎是 RTM VS2015 实际损坏的东西。如果你在没有旧版本 Roslyn 的情况下编译它,它实际上是一个 ConstantExpression
。
4.5 编译器:https://dotnetfiddle.net/XpKg10
Roslyn 编译器:https://dotnetfiddle.net/zeGVdh
在我的机器上安装 Visual Studio 2015 Update 1 后,我发现我的一些单元测试失败了。在做了一些调查之后,我能够将问题减少到这行代码:
Expression<Func<GameObject, bool>> expression = t => t.X == 0 && t.Y == 0 && t.GameObjectType == GameObjectType.WindMill;
将鼠标悬停在表达式变量上时,Visual Studio 版本的结果不同:
对比 2015 年:
VS 2015 更新 1:
对枚举进行比较的逻辑(ServiceStack.OrmLite 代码中的某处)现在的行为有所不同,最终导致枚举未被识别为枚举,从而导致单元测试失败。
我能够使用以下代码重现该问题:
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 中它将进入 UnaryExpression 路径,在 VS 2015 Update 1 中它将进入 ConstantExpression 路径。
如果您在 VS 2015 上编译解决方案,然后将编译后的 .exe 文件复制到 VS 2015 Update 1 系统,它将 运行 与 VS 2015 版本相同(UnaryExpression 路径也是如此)。这表明它与 JIT 无关,而是与构建相关。
我的问题是这是否是故意的? (因为它可能会在简单地重新编译解决方案时破坏现有代码)
这似乎是 RTM VS2015 实际损坏的东西。如果你在没有旧版本 Roslyn 的情况下编译它,它实际上是一个 ConstantExpression
。
4.5 编译器:https://dotnetfiddle.net/XpKg10
Roslyn 编译器:https://dotnetfiddle.net/zeGVdh