2011-11-15 8 views
9

Per curiosità vorrei sapere come implementare meglio una classe che potrebbe essere utilizzato per evitare l'avviso CA1006Come implementare IEnumerable o IDictionary generico per evitare CA1006?

CA1006: Microsoft.Design: Si consideri un disegno in cui 'IReader.Query (String, String) 'non annida il tipo generico' IList (Of IDictionary (Of String, Object)) '.

questo è il metodo che restituisce il tipo generico

public virtual IList<IDictionary<string, object>> Query(
    string fullFileName, 
    string sheetName) 
{ 
    using (var connection = new OdbcConnection(
     this.GetOdbcConnectionString(fullFileName))) 
    { 
     connection.Open(); 
     return connection 
      .Query(string.Format(
       CultureInfo.InvariantCulture, 
       SystemResources.ExcelReader_Query_select_top_128___from__0_, 
       sheetName)) 
      .Cast<IDictionary<string, object>>() 
      .ToList(); 
    } 
} 

Qualcosa di simile

SourceData<T, U> Query(string fullFileName, string sheetName) 
SourceData Query(string fullFileName, string sheetName) 

EDIT:

Seguendo i suggerimenti di Marc ho incapsulato il generico nidificato in questa classe

public class QueryRow : List<KeyValuePair<string, object>> 
{ 
    protected internal QueryRow(IEnumerable<KeyValuePair<string, object>> dictionary) 
    { 
     this.AddRange(dictionary.Select(kvp => kvp)); 
    } 
} 
+0

qual è l'intento della lista di dizionari qui? Quelle righe sono, con valori con chiave (vale a dire le celle accessibili per nome colonna)? –

+0

ogni dizionario è una riga dove ogni chiave è l'intestazione della colonna e il valore è il valore della cella – mrt181

+0

Al posto di '.Cast' non si può usare' .ToDictionary'? – IAbstract

risposta

12

In primo luogo, si noti che è una linea guida , non un errore del compilatore. Un approccio valido qui sarebbe: ignorarlo.

Un altro potrebbe essere - incapsulare; cioè restituire un List<QueryRow>, dove QueryRow è un involucro superficiale su un IDictionary<string,object> con un indicizzatore, cioè

public class QueryRow { 
    private readonly IDictionary<string,object> values; 
    internal QueryRow(IDictionary<string,object> values) { 
     this.values = values; 
    } 
    public object this[string key] { 
     get { return values[key]; } 
     set { values[key] = value; } 
    } 
} 

allora, poiché questa si accede tramite dapper, inserite attraverso:

var data = connection.Query(....) 
     .Select(x => new QueryRow((IDictionary<string,object>)x).ToList() 

Un'altra opzione (che Non mi piace molto), potrebbe essere: restituire DataTable.

si spegne per lavarsi le mani dopo aver digitato DataTable ... gah! due volte ora

+0

ho quasi vomitato quando ho letto restituire DataTable;) – mrt181

+0

ok, ho provato in questo modo. Non funziona. Ricevo questo messaggio 'System.ArgumentNullException: Nome parametro: con bei System.Reflection.Emit.DynamicILGenerator.Emit (OpCode codice operativo, ConstructorInfo con) bei Dapper.SqlMapper.GetClassDeserializer (lettore IDataReader, Int32 startBound, lunghezza Int32, Boolean returnNullIfFirstMissing) in SqlMapper.cs: riga 1227. Quando aggiungo un costruttore senza parametri, Query restituisce un oggetto IEnumerable ma la proprietà value è null. – mrt181

+0

@mrt woah, totalmente non ha notato che questo era "azzimato". Niente nella domanda originale mi ha suggerito "dapper"! Ma: in questo caso, dovresti essere in grado di usare il metodo Query() non generico, quindi lanciarlo a turno, cioè 'connection.Query (....). Seleziona (x => new QueryRow ((IDictionary ) x) .ToList() '- any use? –

Problemi correlati