Code to initialize a .NET object from a CSV file I am initializing the following object from a CSV file:

private class MassUploadUser
    {
        public string email { get; set; }

        public string firstName { get; set; }

        public string lastName { get; set; }

        public string role { get; set; }

        public bool active { get { return true; } }
    }


I later serialize this to JSON using Newtonsoft, and then Post this to a RESTful API. TextFieldParser is from Microsoft.VisualBasic.FileIO by the way.

using (var parser = new TextFieldParser(Program.file))
{
    parser.SetDelimiters(",");

    string[] header = parser.ReadFields();

    while (!parser.EndOfData)
    {
            string[] fields = parser.ReadFields();

            var massUploadUser = new MassUploadUser();
            string password = null;

            for (int i = 0; i &lt; fields.Length; i++)
            {
                switch (header[i])
                {
                    case "First Name":
                        massUploadUser.firstName = fields[i];
                        break;

                    case "Last Name":
                        massUploadUser.lastName = fields[i];
                        break;

                    case "Role":
                        massUploadUser.role = fields[i];
                        break;

                    case "email":
                        massUploadUser.email = fields[i];
                        break;

                    case "Password":
                        password = fields[i];
                        break;
                }
            }

           // After the for loop, I have some additional logic
           // to serialize the newly-created object to JSON
           // and then POST it to a RESTful API
           DoPostToWebService(massUploadUser, password);

          // At this point, we created the new user on the server, so no need
          // to keep the current instance of massUploadUser around
        }


Can this be improved? Is there a more "general" way to do this?
Here is another answer, using Reflection, Expression and Attribute to create a more automated solution.

First you create a couple of custom Attributes to mark fields or properties with the CSV Header Name when it doesn't match the class member name, or to indicate a class member isn't initialized from the CSV:

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
public class CSVColumnName : Attribute {
    public string ColumnName { get; }
    public CSVColumnName(string name) =&gt; ColumnName = name;
}

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
public class CSVNoColumnName : Attribute {
}


Then you can create a static method to build the PropertySetters Dictionary for you by Reflection. You need a couple of extension methods to make MemberInfo easier to work with:

public static Type GetMemberType(this MemberInfo member) {
    switch (member.MemberType) {
        case MemberTypes.Field:
            return ((FieldInfo)member).FieldType;
        case MemberTypes.Property:
            return ((PropertyInfo)member).PropertyType;
        case MemberTypes.Event:
            return ((EventInfo)member).EventHandlerType;
        default:
            throw new ArgumentException("MemberInfo must be if type FieldInfo, PropertyInfo or EventInfo", "member");
    }
}

public static bool GetCanWrite(this MemberInfo member) {
    switch (member.MemberType) {
        case MemberTypes.Field:
            return true;
        case MemberTypes.Property:
            return ((PropertyInfo)member).CanWrite;
        default:
            throw new ArgumentException("MemberInfo must be if type FieldInfo or PropertyInfo", "member");
    }
}


Then you can create the setter lambdas for each field and put them in a Dictionary:

public static class CSVMapping&lt;T&gt; {
    public static Dictionary&lt;string, Action&lt;T, object&gt;&gt; PropertySetters() {
        var t = typeof(T);
        var propsOrFields = t.GetMembers(BindingFlags.Instance | BindingFlags.Public).Where(m =&gt; m.MemberType == MemberTypes.Property || m.MemberType == MemberTypes.Field);

        var ans = new Dictionary&lt;string, Action&lt;T, object&gt;&gt;(StringComparer.OrginalIgnoreCase);
        foreach (var m in propsOrFields) {
            if (!Attribute.IsDefined(m, typeof(CSVNoColumnName)) &amp;&amp; m.GetCanWrite()) {
                var ca = (CSVColumnName)Attribute.GetCustomAttribute(m, typeof(CSVColumnName));
                var csvname = (ca != null) ? ca.ColumnName : m.Name;
                // (T p1, object p2) =&gt; p1.{m.Name} = ({m.Type})p2;
                var paramobj = Expression.Parameter(t);
                var paramval = Expression.Parameter(typeof(object));
                var body = Expression.Assign(Expression.PropertyOrField(paramobj, m.Name), Expression.Convert(paramval, m.GetMemberType()));
                var setter = Expression.Lambda&lt;Action&lt;T, object&gt;&gt;(body, new[] { paramobj, paramval });
                ans.Add(csvname, setter.Compile());
            }
        }
        return ans;
    }
}


Note: You could use reflection to assign values as well, but I figure it is worth the effort to build the lambdas since you presumably will be assigning to the fields often (once per CSV file row).

Now you can annotate the class with CSV information:

private class MassUploadUser {
    public string email { get; set; }

    [CSVColumnName("First Name")]
    public string firstName { get; set; }

    [CSVColumnName("Last Name")]
    public string lastName { get; set; }

    public string role { get; set; }

    [CSVNoColumnName]
    public bool active { get { return true; } }
}


Note: Since active is a read-only property, the PropertySetters method would skip it even if it didn't have the attribute.

Finally, you can convert the CSV file to class members just like my previous answer, using the setters Dictionary to assign read-in values:

var fieldMap = CSVMapping&lt;MassUploadUser&gt;.PropertySetters();

using (var parser = new TextFieldParser(csvFilename)) {
    parser.SetDelimiters(",");

    string[] header = parser.ReadFields();
    var headerMap = header.Select((h, i) =&gt; new { h, i }).ToDictionary(hi =&gt; hi.h, hi =&gt; hi.i);

    while (!parser.EndOfData) {
        string[] fields = parser.ReadFields();

        var massUploadUser = new MassUploadUser();
        foreach (var field in fieldMap.Keys)
            fieldMap[field](massUploadUser, fields[headerMap[field]]);
    }
}