Search code examples
c#csvhelper

csvHelper casting from one object to another in mapper


I am using CsvHelper and am trying to map different properties based on the value of certain property.

Map(m => (m.Prop1 == Enum.Setting1 || m.Prop1 == Enum.Setting2)? m.Prop2 : m.Prop3).Name("MyProperty");

This does not work causing an exception:

System.ArgumentException : Not a member access Parameter name: expression

So I thought I would try and create a new class, inheriting from my base object and then specify these in the mapping type.

Where this new type litterally does this logic in the property instead.

public class NewClassCsv : BaseClass
{
    public string MyProperty
    {
        get { return (this.Prop1 == Enum.Setting1 || this.Prop1 == Enum.Setting2) ? this.Prop2 : this.Prop3; }
    }

I tried to use this new class as my map type, but the object going in to the WriteRecords method of the helper is the base type, and this does not do the cast to change it.

So I tried to do the cast on the mapping:

Map(x => ((NewClassCsv)x).MyProperty);

This also did not work and did not find the property on the object.

Anyone come across this and know how to solve it?

Edit: Custom mapper Section

csvWriter.Configuration.RegisterClassMap<CustomMap>();

public class CustomMap: CsvClassMap<NewClassCsv>
{
    public override void CreateMap()
    {
        Map(m => m.MyProperty).Name("MyProperty");
    }
}

Solution

  • Ok, I was trying to do something that is simply not possible.

    For one, I can't convert from a base class to a derived class - I should have known better.

    Once I realised that I decided that I had a couple of options:

    1. Manually craft the CSV in a foreach (didn't like this approach)
    2. Simply add the display properties to the existing object (this seemed dirty and wrong)
    3. Use AutoMapper and use it to convert from one complex type to the flat structure I want, then just use the properties direct from there.

    I of course went with option 3:

     //mappings for csv download
            Mapper.CreateMap<TeamFeedMessage, MessageCsv>()
                  .ForMember(dest => dest.Alias, opt => opt.MapFrom(t => (t.Message.Contributor.Channel == ChannelEnum.GnipTwitter || t.Message.Contributor.Channel == ChannelEnum.Twitter)? t.Message.Contributor.UserName : t.Message.Contributor.Alias))
    
    public sealed class TeamFeedMessageMap : CsvClassMap<MessageCsv>
    {
        public TeamFeedMessageMap()
        {
            AutoMap();
        }
    }
    

    Then using it:

     var newCsvData = Mapper.Map<IEnumerable<TeamFeedMessage>, List<MessageCsv>>(reportData) as IEnumerable;
    
    csvWriter.Configuration.RegisterClassMap<TeamFeedMessageMap>();
    
    csvWriter.WriteRecords(newCsvData);