Skip to content

Applying a TypeConverter after Automap #1271

Description

@gwintering

I'm having a problem with using a TypeConverter on immutable classes after upgrading from 7.1.0 to the current version (12.1.2). The TypeConverter is designed to call the special factory methods used to construct the immutable classes. I want to use AutoMap to map most of the properties, but apply a TypeConverter for the properties that are a special immutable class, like #505 mentions. The problem is that AutoMap creates a faulty ReferenceMap to the immutable class, and the .TypeConverter call creates and additional MemberMap, without affecting the ReferenceMap. So even though the MemberMap succeeds, the ReferenceMap fails, causing the entire record to fail.

I figured out how to work around the issue by adding ReferenceMaps.Remove(References<ThisMap>(m => m.Problem));, which looks like it also might be viable for #1147 . But in order to get the reference I have to call References<>, which carries a "Meant for internal use only" label.

This problem is similar to #613, but in this case I want to apply a special mapping procedure instead of ignoring the property.

It seems like TypeConverter (and ConvertUsing) should override all generated mappings, so can it be updated to call ReferenceMaps.Remove to clean up anything that AutoMap has done? Otherwise, can the ReferenceMaps.Remove(References<>()) usage be legitimized, possibly with ClassMap method?

Here's an example:

        private class Outer
        {
            // Imagine more properties here, some of them references

            // Then this class needs special conversion logic 
            public Inner Inner { get; set; }
        }

        private class Inner
        {
            public int Immutable { get; }
            // We get a similar issue if the constructor is private
            // and factory methods are exposed
            public Inner(int immutable) =>
                Immutable = immutable;
        }

        public class InnerConverter : ITypeConverter
        {
            public object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData) =>
                // Obviously string => int is already supported,
                // but imagine this is more involved 
                new Inner(int.Parse(text));

            public string ConvertToString(object value, IWriterRow row, MemberMapData memberMapData)
            {
                throw new System.NotImplementedException();
            }
        }

        private class ConverterMap : ClassMap<Outer>
        {
            public ConverterMap()
            {
                AutoMap();
                // Uncommenting this fixes the test
                //ReferenceMaps.Remove(References<ConverterMap>(m => m.Inner));
                Map(m => m.Inner).TypeConverter<InnerConverter>();
            }
        }

		[TestMethod]
		public void AutoMapPlusConverter()
		{
			var queue = new Queue<string[]>();
			queue.Enqueue( new[] { "Inner" } );
			queue.Enqueue( new[] { "9" } );
			queue.Enqueue( null );
			var parserMock = new ParserMock( queue );
			var csv = new CsvReader( parserMock );
			csv.Configuration.RegisterClassMap<ConverterMap>();
			var list = csv.GetRecords<Outer>().ToList();
		}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions