Table of Contents

Attributes

Configuration attributes can be applied on a member, type, or assembly. Attributes on a type can be used to configure classes that you have no direct control over, such as on partial types in auto-generated code. Assembly scoped attributes can be used to configure types in other namespaces or assemblies that you cannot directly modify.

All three attributes in the example below do the same thing. You should annotate directly on the type/member when possible, and use type or assembly scoped attributes only when necessary (e.g. auto-generated code or third party classes).

[assembly: CsvHeader("is_admin", TargetType = typeof(User), MemberName = nameof(User.IsAdmin))]

[CsvHeader("is_admin", MemberName = nameof(IsAdmin))]
class User
{
    [CsvHeader("is_admin")]
    public bool IsAdmin { get; set; }
}

Header names

CsvHeaderAttribute is used to configure the header name used when reading and writing CSV. The first parameter specifies the primary header name. Additional aliases can be provided as follow-up arguments to allow matching the member to alternative header values. The first parameter is always used when writing.

The default header value used is the member's name, e.g., "IsAdmin". See also: CsvOptions<T>.IgnoreHeaderCase and CsvOptions<T>.NormalizeHeader.

[CsvHeader("is_admin")]
public bool IsAdmin { get; set; }

[CsvHeader("id", "user_id")] // allow matching to user_id header
public int Id { get; set; }

Constructor

CsvConstructorAttribute is used to explicitly choose which constructor is used to instantiate a type. The selection process follows these rules:

  1. Constructor with CsvConstructorAttribute
  2. Public parameterless constructor
  3. A single public constructor (if there are multiple or none, an exception is thrown)

Priority for attributes is assembly > type > constructor. If used on a type or assembly, specify the parameter types of the specific constructor.

// all configurations are equivalent
public class User
{
    [CsvConstructor]
    public User(int id, string name) { /* ... */ }

    public User(int id) : this(id, "Guest") { /* ... */ }
}

[CsvConstructor(ParameterTypes = [typeof(int), typeof(string)])]
partial class User;

[assembly: CsvConstructor(TargetType = typeof(User), ParameterTypes = [typeof(int), typeof(string)])]

Required fields

To mark a property, field or parameter as required, use CsvRequiredAttribute. If a required member has no matching field in the CSV header, an exception is thrown.

public class User
{
    public int Id { get; set; }

    [CsvRequired]
    public string Name { get; init; }
}
Note

The following are implicitly treated as required:

  • Properties with init setter
  • Properties with required modifier
  • Constructor parameters without default values

Field order

CsvOrderAttribute can be used to explicitly set the order of fields in CSV. When omitted, 0 is used. Fields are sorted from smallest to largest, with equal values having no guarantees about their order. This attribute also affects the order in which headers are matched to members/parameters.

public class User
{
    [CsvOrder(-1)] // ensure ID is always first
    public int Id { get; set; }

    [CsvOrder(1000)] // ensure name is always last
    public string Name { get; init; }

    // other members omitted
}

Headerless CSV

CsvIndexAttribute can be used to mark members for specific field indexes. These attributes must be set if CsvOptions<T>.HasHeader is false.

public class User
{
    [CsvIndex(0)]
    public int Id { get; set; }

    [CsvIndex(1)]
    public string Name { get; set; }

    [CsvIndex(2)]
    public bool IsAdmin { get; set; }
}

Ignoring members

Use CsvIgnoreAttribute to exclude a member from CSV reading and writing operations.

public class User 
{
    public int Id { get; set; }
    
    [CsvIgnore]
    public DateTime LastModified { get; set; } // This property will be invisible to the library
}

Ignoring indexes

When reading CSV without a header, you can choose to ignore one or more fields when reading by using CsvIgnoredIndexesAttribute on the type. Ignored fields are left empty when writing, and do nothing when reading.

[CsvIgnoredIndexes(1, 3)]
public class User
{
    [CsvIndex(0)]
    public int Id { get; set; }

    [CsvIndex(2)]
    public string Name { get; set; }
}

Overriding converters

Converters can be overridden on a per-member basis by using the CsvConverterAttribute.

class Transaction
{
    [CsvConverter<UnixTimestampConverter>]
    public DateTime Timestamp { get; set; }

    [CsvConverter<MoneyConverter>]
    public decimal Amount { get; set; }
}

You can override either with a converter, or with a factory.

Reading interfaces or abstract classes

Use CsvTypeProxyAttribute to specify a concrete type that should be instantiated when reading an interface or abstract class. The proxy type must be assignable to the target type (interface/abstract class).

[CsvTypeProxy(typeof(User))]
public interface IUser
{
    public int Id { get; }
    public string Name { get; }
}
Note

This feature is still under development and its behavior may change in future releases.