Динамическое сопоставление столбцов CSVHelper

#c# #csvhelper

Вопрос:

Я следую этому примеру, чтобы сопоставить пользовательские имена столбцов с моей моделью класса:

Сопоставление CSVHelper по имени

В этой конкретной части:

 public FooMap()
{
    Map(m => m.Id).Name("ColumnA");
    Map(m => m.Name).Name("ColumnB");
}
 

Можно ли использовать строку в качестве имени столбца вместо ее жесткого кода? Что-то вроде этого —

 public FooMap()
{
    Map("Col1").Name("ColumnA");
    Map("Col2").Name("ColumnB");
}
 

«Col1» и «Col2» являются свойством моей модели класса. Я пытался использовать отражение, но это не сработало:

 Map(x => typeof(MyClassModel).GetProperty("Col1")).Name("ColumnA");
 

Пожалуйста, дайте мне знать, возможно ли то, чего я пытаюсь достичь. Некоторая дополнительная информация — сопоставление столбцов (источник и назначение) хранятся в таблице.

Спасибо!

Комментарии:

1. По опыту я не думаю, что это возможно без использования генератора кода для создания ClassMap во время выполнения.

2. Спасибо за ответ, Джей. Прямо сейчас я просто вручную сопоставляю каждый столбец в моей модели класса с пользовательским именем. Полей много! Вот почему мне интересно, могу ли я использовать динамические имена и просто использовать один цикл, который сопоставил бы все столбцы. Еще раз спасибо.

Ответ №1:

Это должно позволить вам использовать строку для сопоставления как имени свойства, так и имени заголовка.

 void Main()
{
    var mapping = new Dictionary<string, string>
    {
        {"Id","FooId"},
        {"Name","FooName"}
    };
    
    using (var reader = new StringReader("FooId,FooNamen1,Jordan"))
    using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
    {
        var fooMap = new DefaultClassMap<Foo>();

        fooMap.Map(mapping);
        
        csv.Context.RegisterClassMap(fooMap);
        
        var records = csv.GetRecords<Foo>().ToList();
    }   
}

public static class CsvHelperExtensions
{
    public static void Map<T>(this ClassMap<T> classMap, IDictionary<string, string> csvMappings)
    {
        foreach (var mapping in csvMappings)
        {
            var property = typeof(T).GetProperty(mapping.Key);

            if (property == null)
            {
                throw new ArgumentException($"Class {typeof(T).Name} does not have a property named {mapping.Key}");
            }

            classMap.Map(typeof(T), property).Name(mapping.Value);
        }
    }
}

public class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
}

 

Комментарии:

1. Это именно то, что я искал, большое вам спасибо!

Ответ №2:

В качестве другого подхода определите конфигурационный файл XML / JSON, в котором вы можете определить столбцы, которые хотите сопоставить. Напишите анализатор, который мог бы анализировать вашу конфигурацию XML / JSON и возвращать столбцы для динамического сопоставления. Этот подход позволяет сопоставлять любое количество столбцов на лету, без необходимости перекомпиляции кода.

Комментарии:

1. Мое сопоставление столбцов уже находится в таблице. Моя проблема заключается в том, что я не знаю, как сделать исходный и конечный столбцы динамическими как переменные. У вас есть пример кода для вашего сопоставления XML / JSON? Спасибо!