简体   繁体   中英

Mapping to a Dictionary

I was trying to map a csv file so that each record would simply be a Dictionary<string,object> .

I am receiving an

ArgumentException "Not a member access;"

When I try to do this. Code included below:

public class CsvFileReader : FileReader
{
    public CsvFileReader(string path) : base(path){ }

    public IDictionary<string, object> Read()
    {
        var reader = new CsvReader(new StreamReader(Path));
        reader.Read();
        reader.Configuration.RegisterClassMap(new DictionaryClassMap(reader.FieldHeaders));
        return reader.GetRecord<Dictionary<string, object>>();
    }

    private class DictionaryClassMap : CsvClassMap<Dictionary<string, object>>
    {
        private readonly IEnumerable<string> _headers;

        public DictionaryClassMap(IEnumerable<string> headers)
        {
            _headers = headers;
        }

        public override void CreateMap()
        {
            foreach (var header in _headers)
            {
                var localHeader = header;
                Map(x => x[localHeader]);
            }
        }
    } 
}

Unfortunately, there currently is no support for mapping to a Dictionary .

If you try doing GetRecords<Dictionary<string, object>>() , you will get an error.

Types that inhererit IEnumerable cannot be auto mapped. Did you accidentally call GetRecord or WriteRecord which acts on a single record instead of calling GetRecords or WriteRecords which acts on a list of records?

You can't map to a Dictionary either. In a mapping you need to specify a property of the class for the field to be mapped to. The indexer is not a member property which is why you're getting that error.

SOLUTION:

What you CAN do is this:

var record = csv.GetRecord<dynamic>();

You can use it as a dynamic object.

DESIRED SOLUTION

Internally, it uses the ExpandoObject , so you can do this.

var dict = csv.GetRecord<dynamic>() as IDictionary<string, object>;

I was trying to do similar (although not reading all the columns into the Dictionary , just some). So, in case this is of use, (and strongly aided by this answer ) you can have a Dictionary as a property of a class and then populate that (as Josh say's you can't populate a Dictionary on it's own as CsvHelper is expecting a member property to map to).

The below would map to a property DictionaryProperty which is a Dictionary<string,string> of the class MyClassWithDictionaryMapper .

public class MyClassWithDictionaryMapper: ClassMap<MyClassWithDictionary>
{
    public MyClassWithDictionaryMapper(List<string> headers)
    {

        Map(m => m.DictionaryProperty).ConvertUsing
           (row => headers.Select
            (column => new { column, value = row.GetField(column) })
            .ToDictionary(d => d.column, d => d.value)
            );
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM