Povilas Panavas Povilas Panavas - 1 month ago 13
C# Question

Generate c# model class from csv file structure

The goal here is that after inputing csv file, a magic tool would output c# class with the fields from csv. Let's look at example.

Input myFile.csv:

Year,Make,Model
1997,Ford,E350
2000,Mercury,Cougar


Output myFile.cs

public class myFile
{
public string Year;
public string Make;
public string Model;
}


So, the only thing I would need to fix is the types of properties. After that I would use this class with FileHelpers to read csv file. Later it would be mapped to EntityFramework class (using AutoMapper) and saved to database.

Actually, https://csv2entity.codeplex.com/ looks like is doing what I need, but it just doesn't work - I installed it and nothing changed in my Visual studio, no new template appeared. The project is totally dead. Opened source code and ... decided maybe I'll just ask this question in stackoverflow :)

FileHelpers has only a simple wizard, which allows you to manually add fields. But I have 50 fields and this is not the last time I will need to do it, so automated solution is preferred here.

I believe this problem is solved many times before, any help?

Answer

Thank you Bedford, I took your code and added three things:

  • It removes symbols invalid for property names. For example "Order No." will become "OrderNo" property.
  • Ability to add property and class attributes. In my case I need [DelimitedRecord(",")] and [FieldOptional()], because I'm using FileHelpers.
  • Some columns don't have names, so it generates names itself. Naming convention is Column10, Column11 and so on.

Final code:

public class CsvToClass
{
    public static string CSharpClassCodeFromCsvFile(string filePath, string delimiter = ",", 
        string classAttribute = "", string propertyAttribute = "")
    {
        if (string.IsNullOrWhiteSpace(propertyAttribute) == false)
            propertyAttribute += "\n\t";
        if (string.IsNullOrWhiteSpace(propertyAttribute) == false)
            classAttribute += "\n";

        string[] lines = File.ReadAllLines(filePath);
        string[] columnNames = lines.First().Split(',').Select(str => str.Trim()).ToArray();
        string[] data = lines.Skip(1).ToArray();

        string className = Path.GetFileNameWithoutExtension(filePath);
        // use StringBuilder for better performance
        string code = String.Format("{0}public class {1} {{ \n", classAttribute, className);

        for (int columnIndex = 0; columnIndex < columnNames.Length; columnIndex++)
        {
            var columnName = Regex.Replace(columnNames[columnIndex], @"[\s\.]", string.Empty, RegexOptions.IgnoreCase);
            if (string.IsNullOrEmpty(columnName))
                columnName = "Column" + (columnIndex + 1);
            code += "\t" + GetVariableDeclaration(data, columnIndex, columnName, propertyAttribute) + "\n\n";
        }

        code += "}\n";
        return code;
    }

    public static string GetVariableDeclaration(string[] data, int columnIndex, string columnName, string attribute = null)
    {
        string[] columnValues = data.Select(line => line.Split(',')[columnIndex].Trim()).ToArray();
        string typeAsString;

        if (AllDateTimeValues(columnValues))
        {
            typeAsString = "DateTime";
        }
        else if (AllIntValues(columnValues))
        {
            typeAsString = "int";
        }
        else if (AllDoubleValues(columnValues))
        {
            typeAsString = "double";
        }
        else
        {
            typeAsString = "string";
        }

        string declaration = String.Format("{0}public {1} {2} {{ get; set; }}", attribute, typeAsString, columnName);
        return declaration;
    }

    public static bool AllDoubleValues(string[] values)
    {
        double d;
        return values.All(val => double.TryParse(val, out d));
    }

    public static bool AllIntValues(string[] values)
    {
        int d;
        return values.All(val => int.TryParse(val, out d));
    }

    public static bool AllDateTimeValues(string[] values)
    {
        DateTime d;
        return values.All(val => DateTime.TryParse(val, out d));
    }

    // add other types if you need...
}

Usage example:

class Program
{
    static void Main(string[] args)
    {
        var cSharpClass = CsvToClass.CSharpClassCodeFromCsvFile(@"YourFilePath.csv", ",", "[DelimitedRecord(\",\")]", "[FieldOptional()]");
        File.WriteAllText(@"OutPutPath.cs", cSharpClass);
    }
}

There is a link to full code and working example https://github.com/povilaspanavas/CsvToCSharpClass