CSVHelper: замена TypeConverter по умолчанию вызывает исключение TypeConverterException при чтении

Как указано в заголовке, когда я заменяю преобразователь по умолчанию на CSVReader.Configuration.TypeConverterCache, он выдает исключение TypeConverterException, в котором говорится, что он использовал преобразователь по умолчанию вместо замены. Определение преобразователя для этого поля в ClassMap успешно использует заменяющий преобразователь.

Ниже приведена часть кода моего приложения, в которой воспроизводится проблема. В файле .csv, который я использую, есть несколько ненужных строк перед заголовком, поэтому они игнорируются, но я включил их в пример.

class Program {
        static void Main(string[] args) {
            List<Item> items = new List<Item>();        

            var s = new StringBuilder();
            s.Append("WORD,,\r\n");
            s.Append(",地区版本备注,是否测试道具\r\n");
            s.Append("ID,Party,IsActive\r\n");
            s.Append("1,1,0\r\n");
            s.Append("2,1,1\r\n");
            s.Append("3,1,,\r\n");

            Console.WriteLine("Reading with replaced default converter.");
            using (var reader = new StringReader(s.ToString())) {
                using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture)) {
                    csv.Configuration.Delimiter = ",";
                    csv.Configuration.RegisterClassMap<ItemMapWithConverter>();
                    csv.Configuration.TypeConverterCache.RemoveConverter<bool>();
                    csv.Configuration.TypeConverterCache.AddConverter<bool>(new BooleanConverter());

                    Console.WriteLine($"Configuration boolean converter type :: {csv.Configuration.TypeConverterCache.GetConverter<bool>()}");

                    csv.Configuration.ShouldSkipRecord = ShouldSkipRecord;
                    bool foundHeader = false;
                    while (csv.Read()) {
                        try {
                            if (csv.Context.Record[0].StartsWith("ID")) {
                                csv.ReadHeader();
                                foundHeader = true;
                                continue;
                            }

                            if (foundHeader)
                                items.Add(csv.GetRecord<Item>());
                        }
                        catch (TypeConverterException ex) {
                            Console.WriteLine($"Exception :: {ex.Message}");
                            Console.WriteLine($"RawRecord :: {ex.ReadingContext.RawRecord}");
                            continue;
                        }
                    }
                }
            }
            Console.WriteLine();

            Console.WriteLine("Reading with converter defined in ClassMap.");
            using (var reader = new StringReader(s.ToString())) {
                using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture)) {
                    csv.Configuration.Delimiter = ",";
                    csv.Configuration.RegisterClassMap<ItemMapWithoutConverter>();

                    Console.WriteLine($"Configuration boolean converter type :: {csv.Configuration.TypeConverterCache.GetConverter<bool>()}");

                    csv.Configuration.ShouldSkipRecord = ShouldSkipRecord;
                    bool foundHeader = false;
                    while (csv.Read()) {
                        try {
                            if (csv.Context.Record[0].StartsWith("ID")) {
                                csv.ReadHeader();
                                foundHeader = true;
                                continue;
                            }

                            if (foundHeader)
                                items.Add(csv.GetRecord<Item>());
                        }
                        catch (TypeConverterException ex) {
                            Console.WriteLine($"Exception :: {ex.Message}");
                            Console.WriteLine($"RawRecord :: {ex.ReadingContext.RawRecord}");
                            continue;
                        }
                    }
                }
            }

            Console.ReadKey();
        }

        private static bool ShouldSkipRecord(string[] fields) {
            if (string.IsNullOrEmpty(fields[0]))
                return true;
            return false;
        }
    }

    public class Item{
        public int Id { get; set; }
        public int Class { get; set; }
        public bool IsActive { get; set; }

        public Item() { }
    }

    public class ItemMapWithConverter : ClassMap<Item> {
        public ItemMapWithConverter() {
            Map(m => m.Id).Name("ID");
            Map(m => m.Class).Name("Party");
            Map(m => m.IsActive).Name("IsActive");
        }
    }

    public class ItemMapWithoutConverter : ClassMap<Item> {
        public ItemMapWithoutConverter() {
            Map(m => m.Id).Name("ID");
            Map(m => m.Class).Name("Party");
            Map(m => m.IsActive).Name("IsActive").TypeConverter<BooleanConverter>();
        }
    }

    public class BooleanConverter : DefaultTypeConverter {
        public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData) {
            if (string.IsNullOrEmpty(text))
                return false;
            else
                return Convert.ToBoolean(Convert.ToInt32(text));
        }

        public override string ConvertToString(object value, IWriterRow row, MemberMapData memberMapData) {
            if ((bool)value)
                return "1";
            else
                return "0";
        }
    }

Итак, я что-то делаю неправильно при определении конвертеров по умолчанию или это ошибка?


person dvsku    schedule 21.02.2020    source источник


Ответы (1)


Вероятно, нужна лучшая документация. Вам необходимо добавить свой собственный Converter перед регистрацией ClassMap. Кроме того, вам не нужно сначала удалять конвертер bool по умолчанию.

csv.Configuration.Delimiter = ",";
csv.Configuration.TypeConverterCache.AddConverter<bool>(new BooleanConverter());
csv.Configuration.RegisterClassMap<ItemMapWithConverter>();
person David Specht    schedule 21.02.2020