2015-10-16 16 views
9

Ho 3 progetti C#/assiemi, A, B e C. B fa riferimento a una, C fa riferimento a B.di riferimento unico errore necessaria quando si utilizza LINQ

In A:

using System.Collections.Generic; 

namespace A 
{ 
    public class Dict : Dictionary<string, object> {} 
    public class Options: Dict {} 
} 

In B :

using System.Collections.Generic; 
using A; 

namespace B 
{ 
    public class Client 
    { 
     public void M(IDictionary<string, string> d) 
     { 
      var dict = d.ToDict<Options>(); 
     } 
    } 

    public static class Extensions 
    { 
     public static T ToDict<T>(this IDictionary<string, string> dictionary) 
      where T : Dict, new() 
     { 
      return new T(); 
     } 
    } 
} 

In C:

using System.Collections.Generic; 
using B; 

namespace C 
{ 
    public class Worker 
    { 
     public void M() 
     { 
      var client = new Client(); 
      var d = new Dictionary<string, string> { { "k", "v" } }; 
      var strings = new [] { "one", "two" }; // never used 
      client.M(d); 
     } 
    } 
} 

questo tutti i co mpiles.

Se importare il System.Linq spazio dei nomi in Project C e aggiungere la riga strings.Select(s => s); (o qualsiasi altro metodo LINQ) prima della chiamata a client.M(), ottengo un errore di compilazione:

The type 'A.Dict' is defined in an assembly that is not referenced. You must add a reference to assembly 'A, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

Rendere il Extensions classe internal o in movimento in un diverso spazio dei nomi impedisce l'errore.

Dato che B dovrebbe avvolgere A e nascondere i suoi dettagli da C, è sbagliato lasciare che il metodo di estensione sia pubblico. Ma non capisco perché questo viene selezionato dal compilatore solo quando LINQ è incluso.

La presenza di almeno un metodo di estensione fa sì che il compilatore si comporti in modo leggermente diverso?

+1

Impossibile riprodurlo in VS2015, utilizzando framework di destinazione da 3.5 a 4.6 – SWeko

+0

@SWeko: Ho risolto diversi casi, quando Roslyn è più intelligente, quando risolvo le dipendenze. Infatti, lo stesso progetto, compilato con successo usando VS2015, fallisce e richiede un riferimento di assembly aggiuntivo, quando si compila usando VS2013 o precedenti. – Dennis

+0

@SWeko grazie, ho dimenticato di dire che sto usando VS2013. Ho aggiunto un tag. –

risposta

2

L'aggiunta di qualsiasi metodo non risolto attiverà questo errore.

Non riesco a ricordare dove leggo questo, ma il compilatore C# (VS2013) smetterà di risolvere il metodo di estensione quando trova un metodo di non estensione corrispondente. È possibile verificare ciò aggiungendo il seguente codice nel progetto C.

public static class Extensions 
{ 
    public static void M(this Client c, IDictionary<string, string> d) 
    { 
     return; 
    } 
} 

Non causa alcun errore!

Quando un metodo NON viene risolto con il metodo di non estensione (ad esempio, aggiungere "abc".Foo() per causare un errore del compilatore), ora il compilatore C# inizia a esaminare i metodi di estensione. Quando esegue la scansione di B.Extensions.ToDict, non sa cosa sia Dict. Tuttavia, i metadati dell'assieme B indicano al compilatore da A.Dict, quindi viene visualizzato l'errore.

+0

ok, grazie. Sembra strano che il compilatore si preoccupi anche di guardare troppo profondamente un metodo con un nome completamente diverso, ma forse costruisce una cache di tutti i metodi di estensione che può trovare o qualcosa di simile. –

Problemi correlati