2011-11-15 16 views
9

Por curiosidad me gustaría saber cómo implementar mejor una clase que podría ser utilizado para evitar la advertencia CA1006¿Cómo implementar IEnumerable genérico o IDictionary para evitar CA1006?

CA1006: Microsoft.Design: Considere un diseño donde 'IReader.Query (String, String) 'no anida el tipo genérico' IList (Of IDictionary (Of String, Object)) '.

Este es el método que devuelve el tipo genérico

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(); 
    } 
} 

Algo así como

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

EDIT:

Siguiendo las sugerencias de Marc I encapsulado genérico anidada en esta clase

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

¿Cuál es la intención de la lista de diccionarios aquí? es esa filas, con valores clave (es decir, las celdas se accede por nombre de columna)? –

+0

cada diccionario es una fila donde cada clave es el encabezado de columna y el valor es el valor de celda – mrt181

+0

En lugar de '.Cast', ¿no puede usar' .ToDictionary'? – IAbstract

Respuesta

12

En primer lugar, tenga en cuenta que es un diseño guía, no es un error del compilador. Un enfoque válido sería: ignorarlo.

Otro podría ser - encapsularlo; es decir, devolver un List<QueryRow>, donde QueryRow es una envoltura superficial sobre un IDictionary<string,object> con un indizador, es decir

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; } 
    } 
} 

entonces, ya que este se está accediendo a través de apuesto, rellenar a través de:

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

Otra opción (que No soy muy aficionado), podría ser: return DataTable.

se va a lavarse las manos después de escribir DataTable ... gah! dos veces ahora

+0

casi vomité cuando leí DataTable de retorno;) – mrt181

+0

bien, lo intenté de esta manera. No funciona. Me sale este mensaje 'System.ArgumentNullException: ParameterName: con bei System.Reflection.Emit.DynamicILGenerator.Emit (código de operación de código de operación, con ConstructorInfo) bei Dapper.SqlMapper.GetClassDeserializer (lector de IDataReader, Int32 startBound, longitud Int32, Boolean returnNullIfFirstMissing) en SqlMapper.cs: línea 1227. cuando agrego un constructor sin parámetros, Query devuelve un IEnumerable pero la propiedad de valor es nula. – mrt181

+0

@mrt woah, totalmente no se dio cuenta de que esto era "apuesto". ¡Nada en la pregunta original me sugirió "apuesto"! Pero: en este caso, debería poder usar el método Query no genérico() y luego lanzar cada uno por turno, es decir 'connection.Query (....). Select (x => new QueryRow ((IDictionary ) x) .ToList() '- any use? –

Cuestiones relacionadas