2015-12-05 37 views
21

Dopo aver installato Visual Studio 2015 Update 1 sulla mia macchina, ho visto che alcuni dei miei test di unità fallivano. Dopo aver fatto qualche indagine sono stato in grado di ridurre il problema a questa riga di codice:Codice di interruzione espressioni quando compilato utilizzando VS2015 Aggiornamento 1

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

Quando si libra sopra la variabile espressione i risultati sono stati differenti nelle versioni di Visual Studio:

VS 2015: VS 2015

VS 2015 Update 1: VS 2015 Update 1

la logica che stava facendo il confronto per le enumerazioni (da qualche parte in ServiceStack.O rmLite code) ora ha agito in modo diverso, quindi alla fine ha comportato che l'enumerazione non venisse riconosciuta come enumerazione, determinando il fallimento del test unitario.

sono stato in grado di riprodurre il problema utilizzando il seguente codice:

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 
} 

Su VS 2015 andrà nel percorso UnaryExpression, e in VS 2015 Update 1 andrà in percorso ConstantExpression.

Se si compila la soluzione su VS 2015 e quindi si copia il file .exe compilato su un sistema VS 2015 Update 1, verrà eseguito lo stesso della versione VS 2015 (così anche il percorso UnaryExpression). Questo suggerisce che non è correlato ai JIT, ma che costruisce correlato.

La mia domanda sarebbe se questo è previsto? (Poiché potrebbe rompere il codice esistente quando si ricompone semplicemente la soluzione)

+2

Questo appare come un ottimizzazione abbastanza innocente per me. Non mi aspetterei che rompere nulla fino al punto di non funzionare, però: certo, ci vorrebbe un percorso diverso attraverso il codice, quindi i test che controllano quale percorso viene preso si rompono. Tuttavia, il risultato finale della valutazione di questa espressione dovrebbe rimanere lo stesso, e il risultato finale della sua traduzione in qualcos'altro dovrebbe produrre qualcosa di equivalente. – dasblinkenlight

+1

Bene, il codice che si interrompeva eseguiva la serializzazione dell'enumerazione su una query SQL. Ora questo si rompe perché non sa che il valore che viene gestito è in realtà un enum. – Devedse

+0

Forse hai un diferente assemblaggio che contiene quella costante referenziata nella tua espressione? E tu non l'hai ricostruito correttamente ... solo un pensiero. Sei sicuro che il tuo enum sia nella stessa assemblea? –

risposta