Как написать только выбранные поля классов в CSV с помощью CsvHelper?
Я использую CsvHelper
для чтения и записи CSV файлов, и это здорово, но я не понимаю, как писать только выбранные поля типа.
Скажем, у нас было:
using CsvHelper.Configuration;
namespace Project
{
public class DataView
{
[CsvField(Name = "N")]
public string ElementId { get; private set; }
[CsvField(Name = "Quantity")]
public double ResultQuantity { get; private set; }
public DataView(string id, double result)
{
ElementId = id;
ResultQuantity = result;
}
}
}
и мы хотели исключить "количество" CsvField
из результирующего CSV файла, который мы в настоящее время генерируем, например:
using (var myStream = saveFileDialog1.OpenFile())
{
using (var writer = new CsvWriter(new StreamWriter(myStream)))
{
writer.Configuration.Delimiter = '\t';
writer.WriteHeader(typeof(ResultView));
_researchResults.ForEach(writer.WriteRecord);
}
}
Что я могу использовать для динамического исключения поля типа из CSV?
Если это необходимо, мы можем обработать полученный файл, но я не знаю, как удалить весь столбец CSV с помощью CsvHelper
.
Ответы
Ответ 1
Вы можете сделать это:
using (var myStream = saveFileDialog1.OpenFile())
{
using (var writer = new CsvWriter(new StreamWriter(myStream)))
{
writer.Configuration.AttributeMapping(typeof(DataView)); // Creates the CSV property mapping
writer.Configuration.Properties.RemoveAt(1); // Removes the property at the position 1
writer.Configuration.Delimiter = "\t";
writer.WriteHeader(typeof(DataView));
_researchResults.ForEach(writer.WriteRecord);
}
}
Мы заставляем создавать сопоставление атрибутов, а затем модифицируем его, динамически удаляя столбец.
Ответ 2
Недавно мне нужно было добиться аналогичного результата, определив, какие поля включать во время выполнения. Это был мой подход:
-
Создайте файл сопоставления для сопоставления полей, которые мне нужны во время выполнения, передав enum в конструктор класса
public sealed class MyClassMap : CsvClassMap<MyClass>
{
public MyClassMap(ClassType type)
{
switch (type)
{
case ClassType.TypeOdd
Map(m => m.Field1);
Map(m => m.Field3);
Map(m => m.Field5);
break;
case ClassType.TypeEven:
Map(m => m.Field2);
Map(m => m.Field4);
Map(m => m.Field6);
break;
case ClassType.TypeAll:
Map(m => m.Field1);
Map(m => m.Field2);
Map(m => m.Field3);
Map(m => m.Field4);
Map(m => m.Field5);
Map(m => m.Field6);
break;
}
}
}
-
Запишите записи на использование конфигурации отображения
using (var memoryStream = new MemoryStream())
using (var streamWriter = new StreamWriter(memoryStream))
using (var csvWriter = new CsvWriter(streamWriter))
{
csvWriter.Configuration.RegisterClassMap(new MyClassMap(ClassType.TypeOdd));
csvWriter.WriteRecords(records);
streamWriter.Flush();
return memoryStream.ToArray();
}
Ответ 3
Отметьте поле следующим образом:
[CsvField( Ignore = true )]
public double ResultQuantity { get; private set; }
Обновление: Nevermind. Я вижу, вы хотите сделать это во время выполнения, а не компилировать время. Я оставлю это красным флагом для всех, кто может совершить ту же ошибку.
Ответ 4
У меня была похожая проблема с моим кодом, и я исправил ее с помощью следующего кода.
Вы можете сделать это:
var ignoreQuantity = true;
using (var myStream = saveFileDialog1.OpenFile())
{
using (var writer = new CsvWriter(new StreamWriter(myStream)))
{
var classMap = new DefaultClassMap<DataView>();
classMap.AutoMap();
classMap.Map(m => m.ResultQuantity).Ignore(ignoreQuantity)
writer.Configuration.RegisterClassMap(classMap);
writer.Configuration.Delimiter = "\t";
writer.WriteHeader(typeof(DataView));
_researchResults.ForEach(writer.WriteRecord);
}
}
Ответ 5
Я должен был решить это также: у меня есть пара дюжин типов записей с общим базовым классом плюс общее поле, которое все они должны игнорировать:
// Nothing special here
internal class MyClassMap<T> : ClassMap<T> where T : MyRecordBaseClass
{
public MyClassMap()
{
AutoMap();
Map( m => m.SOME_FIELD ).Ignore();
}
}
Эта часть, как правило, хорошо документирована, а не динамическая часть.
Но один класс нуждался в особом соусе, игнорируя другое поле динамически, и хотя я мог бы создать отдельный класс карты, это не масштабировалось, поскольку я ожидаю, что их будет намного больше, поэтому я наконец-то понял, как это сделать. должным образом:
...
// special processing for *one* record type
csvwriter.Configuration.RegisterClassMap<MyClassMap<ONE_RECORD_TYPE>>();
if (ShouldIgnore)
{
var map = csvwriter.Configuration.Maps.Find<ONE_RECORD_TYPE>();
map.Map( m => m.SOME_OTHER_FIELD ).Ignore();
}
...
Это работало на CsvHelper версий 7.1.1 и 12.1.1.