2015-12-05 7 views
21

Nach der Installation von Visual Studio 2015 Update 1 auf meinem Computer sah ich, dass einige meiner Komponententests fehlgeschlagen. Nach einigen Untersuchungen tun konnte ich das Problem auf diese Zeile Code reduzieren:Ausdrücke, die Code beim Kompilieren mit VS2015 Update 1

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

Wenn über den Ausdruck Variable schwebt die Ergebnisse in den Versionen von Visual Studio unterschiedlich waren:

VS 2015: VS 2015

VS 2015 Update 1: VS 2015 Update 1

die Logik, die den Vergleich für die Aufzählungen tat (irgendwo in ServiceStack.O rmLite code) wurde nun anders gehandhabt, was schließlich dazu führte, dass das Enum nicht als Enum erkannt wurde, was zum fehlgeschlagenen Komponententest führte.

Ich war in der Lage, das Problem mit dem folgenden Code zu reproduzieren:

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 
} 

auf VS 2015 in dem UnaryExpression Weg zu gehen, und in VS 2015 Update 1 wird den ConstantExpression Weg gehen.

Wenn Sie die Lösung auf VS 2015 kompilieren und dann die kompilierte .exe-Datei auf ein VS 2015 Update 1-System kopieren, wird es genauso ausgeführt wie die VS 2015-Version (also auch der UnaryExpression-Pfad). Dies deutet darauf hin, dass es sich nicht um eine JIT handelt, sondern um eine verwandte Beziehung.

Meine Frage wäre, wenn dies beabsichtigt ist? (Da es bestehenden Code brechen könnte, wenn die Lösung einfach neu kompiliert wird)

+2

Dies sieht aus wie eine ziemlich unschuldig Optimierung zu mir. Ich würde allerdings nicht erwarten, dass etwas so funktioniert, dass es nicht funktioniert: Sicher, es würde einen anderen Weg durch den Code gehen, also würden Tests, die prüfen, welcher Pfad genommen wird, brechen. Das Endergebnis der Auswertung dieses Ausdrucks sollte jedoch gleich bleiben, und das Endergebnis der Übersetzung in etwas anderes sollte etwas Äquivalentes ergeben. – dasblinkenlight

+1

Nun, der Code, der brach, hat die Serialisierung von Enums zu einer SQL-Abfrage gemacht. Jetzt bricht das, weil es nicht weiß, dass der Wert, der gehandhabt wird, tatsächlich eine Aufzählung ist. – Devedse

+0

Vielleicht haben Sie eine andere Assembly, die diese Konstante enthält, auf die in Ihrem Ausdruck verwiesen wird? Und du hast es einfach nicht richtig umgebaut ... nur ein Gedanke. Bist du dir sicher, dass dein Enum in derselben Baugruppe steht? –

Antwort