Search code examples
c#.net.net-coredynamicpropertyinfo

Dynamic assigned Properties for CsvHelper.Configuration.ClassMap<T>


I want to use CsvHelper.Configuration.ClassMap by dynamically assigned properties.

Usually you map a Property like this in a static manner: You have to assign each property and its 'text to display'.

using CsvHelper.Configuration;

        public sealed class CleanSQLRowDescriptorMap : ClassMap<CleanSQLRowDescriptor>
        {
            public CleanSQLRowDescriptorMap()
            {
                Map(f => f.OriginalIndex).Name("Original Index");
                Map(f => f.OriginalRow).Name("Original Row");
            }
       }

I want to do the following:

using CsvHelper.Configuration;

        public sealed class CleanSQLRowDescriptorMap : ClassMap<CleanSQLRowDescriptor>
        {
            public CleanSQLRowDescriptorMap()
            {
                // Filter by attribute (implementation returns PropertyInfo List)
                List<PropertyInfo> mappedProperties = CleanSQLRowDescriptor.Create().FilterPropertiesByAttribute();

                // Dynamically assign each property and its assigned 'attribute value'  
                // At the moment I mapped the PropertyInfo.Name, but I actually need to use the Property as the static example above.  
                // Also need to figure out how to get the Attribute value (DisplayName in this example).
                mappedProperties.ForEach(prop => Map(f => prop.Name).Name(prop.Name));
            }
       }

I currently have the following method used above:

            [DisplayName("Original Index")]
            public int OriginalIndex { get; set; }

            [DisplayName("Original Row")]
            public string OriginalRow { get; set; }

            public string DonotWantToAssignThis { get; set; }

            public List<PropertyInfo> FilterPropertiesByAttribute()
            {
                // This function already returns only the attributes that use
                // [DisplayName] and other attributes defined for other properties, 
                // ignoring other properties that do not have any of these attributes.

                return properties;
            }

How can I use the PropertyInfo List of items to dynamically assign the ClassMap? I want to create a base class with these attributes as filters and all the classes implementing this base class would have the same capability, making it easier to 'maintain the mappings'.


Solution

  • I managed to figure it out, VS Code did not give me all the overloads for Map() function, so I missed overloads.

    This one is used in all examples:

    MemberMap<TClass, TMember> Map<TMember>(Expression<Func<TClass, TMember>> expression, bool useExistingMap = true);
    

    I found this inside JoshClose/CSVHelper:

    public MemberMap Map(Type classType, MemberInfo member, bool useExistingMap = true)
    

    So instead of using 'Expression that requires the property name as TMember' which does not take the type I can now assign the MemberInfo directly.

    The code below just shows a solution for a single attribute [DisplayName] by using its .DisplayName property value.
    For additional Attributes like I have at the moment, I will need to handle the property value differently:

    mappedProperties.ForEach(prop =>
    {
       Map(typeof(CleanSQLRowDescriptor), prop).Name(prop.GetCustomAttribute<DisplayNameAttribute>().DisplayName);
    });