2011-01-06 6 views
8

Assumere questa catena di riferimenti dllPerché chiamare IEnumerable <string> .Count() crea una dipendenza aggiuntiva dall'assembly?

Tests.dll >> Automation.dll >> White.Core.dll 

con la seguente riga di codice nella Tests.dll, dove tutto si basa

result.MissingPaths 

Ora quando cambio a questo

result.MissingPaths.Count() 

I ottenere il seguente errore di generazione per Tests.dll "White.UIItem non è definito in un assembly a cui non viene fatto riferimento. È necessario aggiungere un riferimento a White.Core.dll." E non voglio farlo perché rompe la mia stratificazione.

Ecco la definizione del tipo di risultato, che è in Automation.dll

public class HasResult 
     { 
      public HasResult(IEnumerable<string> missingPaths) 
      { MissingPaths = missingPaths;   } 

      public IEnumerable<string> MissingPaths { get; set; } 

      public bool AllExist 
      { 
       get { return !MissingPaths.Any(); } 
      } 
     } 

giù la catena chiamata viene creato il parametro di ingresso a questa ctor via (La classe TreeNode è in White.Core.dll)

assetPaths.Where(assetPath => !FindTreeNodeUsingCache(treeHandle, assetPath)); 

Perché questa perdita di dipendenza quando si chiama Count() su IEnumerable? Ho quindi sospettato che questa valutazione pigra causasse questo (per qualche ragione), quindi ho inserito un ToArray() nella riga sopra ma non ha funzionato.

Aggiornamento 2011 01 07: Curioso e curioso! non verrà creato finché non aggiungo un riferimento a White.Core. Quindi aggiungo un riferimento e lo costruisco (per trovare l'elusiva fonte di dipendenza). Aprilo in Reflector e gli unici riferimenti elencati sono Automation, mscorlib, System.core e NUnit. Quindi il compilatore ha gettato via il riferimento Bianco in quanto non era necessario. ILDASM conferma anche che non esiste una voce White AssemblyRef.

Qualche idea su come arrivare alla fine di questa cosa (principalmente per le ragioni "ora voglio sapere perché")? Quali sono le probabilità che si tratti di un bug VS2010/MSBuild?

Aggiornamento 2011 01 07 # 2 Come da suggerimento di Shimmy, provato a chiamare il metodo explcitly come un metodo di estensione

Enumerable.Count(result.MissingPaths) 

e si ferma cribbing (non so perché).
Tuttavia ho spostato un po 'di codice in seguito e ora sto ricevendo lo stesso problema in una posizione diversa utilizzando IEnumerable - questa volta la lettura e il filtraggio di righe su un file su disco (totalmente estraneo al Bianco). Sembra che sia una "correzione dei sintomi".
var lines = File.ReadLines(aFilePath).ToArray(); ancora una volta, se rimuovo il ToArray() viene compilato di nuovo - sembra che qualsiasi metodo che fa valutare l'enumerabile (ToArray, Count, ToList, ecc.) Lo fa. Mi permetta di cercare di ottenere un lavoro piccolo-app di demo questo problema ...

Aggiornamento 2011 01 07 # 3 Accidenti! Ulteriori informazioni .. Si scopre che il problema è solo in un file sorgente: questo file è LINQ-phobic. Qualsiasi chiamata a un metodo di estensione enumerabile deve essere esplicitamente richiamata. I refactoring che ho fatto hanno causato il trasferimento di un nuovo metodo in questo file sorgente, che aveva alcuni LINQ :) Ancora nessun indizio sul motivo per cui questa classe non piaccia LINQ.

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using G.S.OurAutomation.Constants; 
using G.S.OurAutomation.Framework; 
using NUnit.Framework; 

namespace G.S.AcceptanceTests 
{ 
    public abstract class ConfigureThingBase : OurTestFixture 
    { 
     .... 
     private static IEnumerable<string> GetExpectedThingsFor(string param) 
     { 
       // even this won't compile - although it compiles fine in an adjoining source file in the same assembly 
       //IEnumerable<string> s = new string[0]; 
       //Console.WriteLine(s.Count()); 



       // this is the line that is now causing a build failure 
      // var expectedInfo = File.ReadLines(someCsvFilePath)) 
//     .Where(line => !line.StartsWith("REM", StringComparison.InvariantCultureIgnoreCase)) 
//     .Select(line => line.Replace("%PLACEHOLDER%", param)) 
//     .ToArray(); 

       // Unrolling the LINQ above removes the build error 

      var expectedInfo = 
       Enumerable.ToArray(
        Enumerable.Select(
         Enumerable.Where(
          File.ReadLines(someCsvFilePath)), 
          line => !line.StartsWith("REM", StringComparison.InvariantCultureIgnoreCase)), 
         line => line.Replace("%PLACEHOLDER%", param))); 

Aggiornamento 2011 01 11 # 4 ristretto la scelta a quello che sembra il colpevole, ma nessun movente :)
ripresa la quest post il fine settimana .. e utilizzando il processo evergreen di eliminazione, è stato in grado di entra nel bit offendente. Il problema è la seguente direttiva using nel file di origine in Tests.dll

using G.S.OurAutomation.Framework; 

dopo sono andato dopo il sospetto più probabile all'interno di questo spazio dei nomi e ho avuto WhiteExtensions sotto i riflettori.

namespace G.S.OurAutomation.Framework 
{ 
    public static class WhiteExtensions 
    { 
     public static T PollAndGet<T>(this Window parentWindow, string automationId) where T : UIItem ... 
     public static Window WaitForWindowWithTitle(this Application application, string windowTitle) ... 
     public static bool HasTreeNode(this Tree treeHandle, string assetPath) ... 
     public static HasTreeNodesResult HasTreeNodes(this Tree treeHandle, IEnumerable<string> assetPaths)... 
    } 
} 

Questo ha portato a 3 correzioni, che funzionano entrambe.

  1. Trasforma i metodi di estensione in normali metodi statici.
  2. Spostare questa classe in un subnamespace G.S.OurAutomation.Framework.White
  3. rendere questo una classe interna (in quanto è destinato per il consumo interno .. ancora una volta la linea guida di scegliere il modificatore di accesso più restrittivo mi morde.)

Anche se la mia istanza specifica è corretta, questo aggiornamento può aiutare qualcuno a spiegarne il motivo? Se non shimmy ottiene il segno di spunta :) per indicare verso la giusta direzione.

+2

potresti fornire altro codice? E forse rinominare le DLL in qualcosa di più significativo? Forse W.Type non è referenziato dove viene dichiarato un metodo di estensione? – James

+0

Prova ad aggiungere W.dll come riferimento al progetto T. – Steven

+0

@James - Assegnato agli assembly :) Quello che sta facendo il codice (in breve) è: Verificare se alcuni nodi esistono in una struttura mostrata sulla GUI? risultato è un tipo che include un valore di successo booleano + un elenco di nodi mancanti, se presenti. Quindi Tests.dll utilizza Automation.dll - Driver.HasNodes() per fare la sua cosa, tuttavia l'impl. il dettaglio che Automation.dll utilizza per eseguire il lavoro non dovrebbe strisciare fuori dal livello di automazione. Il codice prevede la restituzione di un oggetto IEnumerable (percorsi completi Root \ parent \ child) dal livello interno al client per la segnalazione degli errori. – Gishu

risposta

0

Come di cambiare

public HasResult(IEnumerable<string> missingPaths) 
{ MissingPaths = missingPaths;   } 

a

public HasResult(IEnumerable<string> missingPaths) 
{ MissingPaths = missingPaths.ToArray();   } 

dovrebbe eliminare scenari lazy loading in tutti i casi in cui viene utilizzato risultato.

+0

provato questo - non ha funzionato come menzionato verso la fine del mio post – Gishu

+0

@Gishu, è stato suggerito nel caso in cui, hai perso un luogo dove viene costruito il risultato. Un'altra possibilità è il setter MissingPaths utilizzato in A.dll altrove - puoi renderlo privato? Inoltre, qual è il tipo di W per il quale il compilatore è cribbing? – VinayC

+0

Richiede un tipo UIItem definito in White.dll, tuttavia, ho mantenuto Tests.dll White gratuitamente per tutto questo tempo. (Ha trovato anche una sostituzione per il doppio controllo). Inoltre, ho provato a forzare la valutazione a diff in cima allo stack delle chiamate ma non funziona. – Gishu

4

Provare a chiamare System.Linq.Enumerable.Count(result.MissingPaths) (con o senza il riferimento completo dello spazio dei nomi).

Count è un metodo di estensione, è possibile chiamarlo esplicitamente.

Aggiornamento dopo di Gishu Aggiornamento # 2:

La ragione di tutto è lo stesso, le funzioni ToArray, Count, ToList ecc, sono tutti i metodi di estensione dichiarati nel System.Linq.Enumerable.

BTW, importante: hai fatto doppio controllo che la System.Linq namespace è importata (using System.Linq) al file? potrebbe persino risolvere tutti i tuoi problemi.

+0

Questo ha funzionato ma non so perché! Sono troppo felice per questo. Un paio di refactoring più tardi .. Ricevo lo stesso errore in un altro posto dove sto usando nuovamente IEnumerable - questa volta per leggere le righe da un file e filtrare alcune righe indesiderate. Qualunque motivo specifico l'hai suggerito ... – Gishu

+1

Poiché IEnumerable non contiene la funzione Count, qualcosa nello spazio dei nomi System.Linq (questo è chiamato un metodo di estensione). http://msdn.microsoft.com/en-us/library/bb383977.aspx –

+0

@Gishu: ho aggiornato il mio post. – Shimmy

1

Il compilatore presumibilmente aveva bisogno di vedere White.Core.dll per capire se esisteva un metodo Count() definito sulla classe. Dal momento che non è stato utilizzato il Conteggio del metodo di estensione IEnumerable <> e quindi non ha avuto bisogno di White.Core.dll dopo tutto, ma non poteva sapere che senza esaminarlo.

Ma non riesco a spiegare come potrebbe essere il caso di IEnumerable<string> a meno che il compilatore non stia controllando che non si stia utilizzando la covarianza ??

+0

" ... Count() metodo definito sulla tua classe "quale classe intendevi? HasResult? – Gishu

Problemi correlati