9

Out of curiosity i would like to know how to best implement a class that could be used to avoid the CA1006 warning

CA1006 : Microsoft.Design : Consider a design where 'IReader.Query(String, String)' doesn't nest generic type 'IList(Of IDictionary(Of String, Object))'.

This is the method that returns the generic type

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

Something like

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

EDIT:

Following Marc's suggestions I encapsulated the nested generic in this class

public class QueryRow : List<KeyValuePair<string, object>>
{
    protected internal QueryRow(IEnumerable<KeyValuePair<string, object>> dictionary)
    {
        this.AddRange(dictionary.Select(kvp => kvp));
    }
}
mrt181
  • 5,080
  • 8
  • 66
  • 86

1 Answers1

12

Firstly, note that it is a design guideline, not a compiler error. One valid approach here would be: ignore it.

Another might be - encapsulate it; i.e. return a List<QueryRow>, where QueryRow is a shallow wrapper over an IDictionary<string,object> with an indexer, i.e.

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

then, since this is being accessed via dapper, fill via:

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

Another option (that I'm not hugely fond of), might be: return DataTable.

goes off to wash his hands after typing DataTable... gah! twice now

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • ok, i tried it this way. Does not work. I get this message `System.ArgumentNullException: Parametername: con bei System.Reflection.Emit.DynamicILGenerator.Emit(OpCode opcode, ConstructorInfo con) bei Dapper.SqlMapper.GetClassDeserializer(IDataReader reader, Int32 startBound, Int32 length, Boolean returnNullIfFirstMissing) in SqlMapper.cs: line 1227.` when i add a parameterless constructor, Query returns an IEnumerable but the value property is null. – mrt181 Nov 15 '11 at 19:00
  • @mrt woah, totally didn't notice that this was "dapper". Nothing in the original question suggested "dapper" to me! But: in this case, you should be able to use the non-generic Query() method then cast each in turn, i.e. `connection.Query(....).Select(x => new QueryRow((IDictionary)x).ToList()` - any use? – Marc Gravell Nov 15 '11 at 19:30
  • i thought the tag dapper would have been obvious :) – mrt181 Nov 15 '11 at 19:42
  • @mrt181 I obviously missed the tags – Marc Gravell Nov 15 '11 at 20:27