StringConverterCreateNullable Method

Creates a new TypeConverter<String?> instance.

Definition

Namespace: FolkerKinzel.CsvTools.Mappings.TypeConverters
Assembly: FolkerKinzel.CsvTools.Mappings (in FolkerKinzel.CsvTools.Mappings.dll) Version: 1.1.0+1263e8243dc2cd78095f678f813d7d9c52ea4315
C#
public static TypeConverter<string?> CreateNullable()

Return Value

TypeConverterString
The newly created TypeConverter<String?> instance. Its DefaultValue will be null.

Example

  Note

In the following code examples - for easier readability - exception handling has been omitted.

Saving the contents of a DataTable as a CSV file and importing data from a CSV file into a DataTable:

C#
using FolkerKinzel.CsvTools;
using FolkerKinzel.CsvTools.Mappings;
using System.Data;
// A namespace alias helps to avoid name conflicts
// with the converters from System.ComponentModel
using Conv = FolkerKinzel.CsvTools.Mappings.TypeConverters;

namespace Examples;

internal static class DataTableExample
{
    public static void DataTableWriteReadCsv(string filePath)
    {
        using var dataTable = new DataTable();

        dataTable.Columns.Add(new DataColumn("not_used", typeof(int)));
        dataTable.Columns.Add(new DataColumn("name"));
        dataTable.Columns.Add(new DataColumn("subject"));
        dataTable.Columns.Add(new DataColumn("day", typeof(DayOfWeek)));
        dataTable.Columns.Add(new DataColumn("lesson start", typeof(TimeOnly)));

        // The DataColumn.Caption property allows you to override the DataColumn.ColumnName property
        // when the ColumnName does not meet C# identifier requirements. The values ​​of the
        // DataColumn.Caption properties must be unique for CSV serialization (case-insensitive,
        // like DataColumn.ColumnName).
        dataTable.Columns["lesson start"]!.Caption = "begin";

        _ = dataTable.Rows.Add(
            [4711, "Susi Meyer", "Piano", DayOfWeek.Wednesday, new TimeOnly(14, 30, 0)]);
        _ = dataTable.Rows.Add(
            [0, "Carl Czerny", "Piano", DayOfWeek.Thursday, new TimeOnly(15, 15, 0)]);
        _ = dataTable.Rows.Add(
            [111, "Frederic Chopin", "Piano"]);

        // Store the stringConverter because you can reuse the same 
        // converter for more than one property in CsvRecordWrapper.
        Conv::TypeConverter<object> stringConverter
            = Conv::StringConverter.CreateNullable().ToDBNullConverter();

        // Each dynamic property name of the CsvMapping has to have a corresponding column in
        // the DataTable - corresponding in the DataColumn.Caption property (case-insensitive)
        // and the accepted data type. Mapping properties and DataColumns don't need to
        // correspond in their number and order and they don't need to match the columns of
        // the CSV file:
        CsvMapping mapping = CsvMappingBuilder
            .Create()
            .AddProperty("Name", stringConverter)
            .AddProperty("Subject", stringConverter)
            .AddProperty("Day", new Conv::EnumConverter<DayOfWeek>(format: "G")
                                .ToNullableConverter()
                                .ToDBNullConverter())
            .AddProperty("Begin", ["begin", "*start"], new Conv::TimeOnlyConverter()
                                                       .ToNullableConverter()
                                                       .ToDBNullConverter())
            .Build();

        // Write the CSV file:
        // (The CSV column names and the CsvMapping determine which DataColumns will be
        // part of the CSV and their order in the CSV file.)
        dataTable.WriteCsv(filePath,
                           mapping,
                           csvColumnNames: ["Subject", "Lesson Start", "Name", "Day", "Reserved"]);

        dataTable.Clear();

        // Refill the DataTable from the CSV-file:
        dataTable.ReadCsv(filePath, mapping);

        Console.WriteLine("Csv file:");
        Console.WriteLine();
        Console.WriteLine(File.ReadAllText(filePath));
        Console.WriteLine();
        Console.WriteLine("Content of the refilled DataTable:");
        Utility.WriteConsole(dataTable);
    }
}
/* 
Console output:

Csv file:

Subject,Lesson Start,Name,Day,Reserved
Piano,14:30:00,Susi Meyer,Wednesday,
Piano,15:15:00,Carl Czerny,Thursday,
Piano,,Frederic Chopin,,

Content of the refilled DataTable:
<DBNull>        Susi Meyer      Piano           3               14:30
<DBNull>        Carl Czerny     Piano           4               15:15
<DBNull>        Frederic Chopin Piano           <DBNull>        <DBNull>
*/

Object serialization with CSV:

C#
using FolkerKinzel.CsvTools;
using FolkerKinzel.CsvTools.Mappings;
using System.Text;
// A namespace alias helps to avoid name conflicts
// with the converters from System.ComponentModel
using Conv = FolkerKinzel.CsvTools.Mappings.TypeConverters;

namespace Examples;

internal sealed record Pupil(string? Name, string? Subject, DayOfWeek? LessonDay, TimeOnly? LessonBegin);

internal static class ObjectSerializationExample
{
    public static void CsvReadWritePupils(string filePath)
    {
        Pupil[] pupils = [
                            new("Susi", "Piano", DayOfWeek.Wednesday, new TimeOnly(14, 30)),
                            new("Carl Czerny", "Piano", DayOfWeek.Thursday, new TimeOnly(15, 15)),
                            new("Frederic Chopin", "Piano", null, null)
                         ];

        // A converter can be reused for more than one DynamicProperty:
        Conv::TypeConverter<string?> stringConverter = Conv::StringConverter.CreateNullable();

        // Initialize a CsvMapping that maps the data from the CSV-Columns and converts it to the right data type.
        // Aliases with wildcards can be used to match the column-headers of the CSV file. 
        CsvMapping mapping = CsvMappingBuilder
            .Create()
            .AddProperty("Name", ["*name"], stringConverter)
            .AddProperty("Subject", ["*subject", "*fach"], stringConverter)
            .AddProperty("LessonDay", ["*day", "*tag"], new Conv::EnumConverter<DayOfWeek>().ToNullableConverter())
            .AddProperty("LessonBegin", ["*begin?"], new Conv::TimeOnlyConverter().ToNullableConverter())
            .Build();

        // Create a CSV-File:
        pupils.SaveCsv(filePath,
                       mapping,
                       static (pupil, mapping) =>
                       {
                           mapping.Name = pupil.Name;
                           mapping.Subject = pupil.Subject;
                           mapping.LessonDay = pupil.LessonDay;
                           mapping.LessonBegin = pupil.LessonBegin;
                       },
                       columnNames:
                       ["Unterrichtstag", "Unterrichtsbeginn", "Vollständiger Name", "Unterrichtsfach"]);

        Console.WriteLine(File.ReadAllText(filePath));
        Console.WriteLine();

        // Read the CSV file:
        using CsvReader<Pupil> pupilsReader =
           CsvConverter.OpenRead<Pupil>(filePath,
                                        mapping,
                                        static mapping => new Pupil(mapping.Name,
                                                                    mapping.Subject,
                                                                    mapping.LessonDay,
                                                                    mapping.LessonBegin));
        pupils = [.. pupilsReader];

        // Write the results to the Console:
        foreach (Pupil pupil in pupils)
        {
            Console.WriteLine(pupil);
        }
    }
}

/*
Console output: 

Unterrichtstag,Unterrichtsbeginn,Vollständiger Name,Unterrichtsfach
3,14:30:00,Susi,Piano
4,15:15:00,Carl Czerny,Piano
,,Frederic Chopin,Piano

Pupil { Name = Susi, Subject = Piano, LessonDay = Wednesday, LessonBegin = 14:30 }
Pupil { Name = Carl Czerny, Subject = Piano, LessonDay = Thursday, LessonBegin = 15:15 }
Pupil { Name = Frederic Chopin, Subject = Piano, LessonDay = , LessonBegin =  }
*/

See Also