Created

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist

Set FileHelper's FileHelperEngine.HeaderText via reflection

View FileHelpersTypeExtensions.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
 
// see http://stackoverflow.com/questions/3975741/column-headers-in-csv-using-filehelpers-library/8258420#8258420
 
// ReSharper disable CheckNamespace
namespace FileHelpers
// ReSharper restore CheckNamespace
{
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class FieldTitleAttribute : Attribute
{
public FieldTitleAttribute(string name)
{
if (name == null) throw new ArgumentNullException("name");
Name = name;
}
 
public string Name { get; private set; }
}
 
public static class FileHelpersTypeExtensions
{
public static IEnumerable<string> GetFieldTitles(this Type type)
{
var fields = from field in type.GetFields(
BindingFlags.GetField |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance)
where field.IsFileHelpersField()
select field;
 
return from field in fields
let attrs = field.GetCustomAttributes(true)
let order = attrs.OfType<FieldOrderAttribute>().Single().GetOrder()
let title = attrs.OfType<FieldTitleAttribute>().Single().Name
orderby order
select title;
}
 
public static string GetCsvHeader(this Type type)
{
return String.Join(",", type.GetFieldTitles());
}
 
static bool IsFileHelpersField(this FieldInfo field)
{
return field.GetCustomAttributes(true)
.OfType<FieldOrderAttribute>()
.Any();
}
 
static int GetOrder(this FieldOrderAttribute attribute)
{
// Hack cos FieldOrderAttribute.Order is internal (why?)
var pi = typeof(FieldOrderAttribute)
.GetProperty("Order",
BindingFlags.GetProperty |
BindingFlags.Instance |
BindingFlags.NonPublic);
 
return (int)pi.GetValue(attribute, null);
}
}
}
View FileHelpersTypeExtensions.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
[DelimitedRecord(","), IgnoreFirst(1)]
public class Person
{
// Must specify FieldOrder too
[FieldOrder(1), FieldTitle("Name")]
string name;
 
[FieldOrder(2), FieldTitle("Age")]
int age;
}
 
...
 
var engine = new FileHelperEngine<Person>
{
HeaderText = typeof(Person).GetCsvHeader()
};
 
...
 
engine.WriteFile(@"C:\people.csv", people);
mrtns commented

Thanks for this gist Richard!

I found the "FieldTitle" attribute to be a bit redundant, so I just use the field name instead:

public static class FileHelperUtils {
    public static IEnumerable<string> GetFieldTitles(this Type type) 
    {
        var fields = from field in type.GetFields(
            BindingFlags.GetField |
            BindingFlags.Public |
            BindingFlags.NonPublic |
            BindingFlags.Instance)
                     where field.IsFileHelpersField()
                     select field;

        return from field in fields
               let attrs = field.GetCustomAttributes(true)
               let order = attrs.OfType<FieldOrderAttribute>().Single().GetOrder()
               let title = field.Name
               orderby order
               select title;
    }

    public static string GetCsvHeader(this Type type)
    {
        return String.Join(",", type.GetFieldTitles());
    }

    static bool IsFileHelpersField(this FieldInfo field)
    {
        return field.GetCustomAttributes(true)
            .OfType<FieldOrderAttribute>()
            .Any();
    }

    static int GetOrder(this FieldOrderAttribute attribute)
    {
        // Hack cos FieldOrderAttribute.Order is internal (why?)
        var pi = typeof(FieldOrderAttribute)
            .GetProperty("Order",
                BindingFlags.GetProperty |
                BindingFlags.Instance |
                BindingFlags.NonPublic);

        return (int)pi.GetValue(attribute, null);
    }
}
Owner

Np. We had to use FieldTitle because we were using property-backed fields and wanted uppercase column names in the CSV (the version of FileHelpers didn't support properties... not sure how this is possible in 2011)

Additional option: use a delimiter as seperator. Too bad the original delimiter is internal, so I had to create a custom class; Joiner.

Code:

    public static string GetCsvHeader(this Type type) {
        return String.Join(type.GetCustomAttributes(true).OfType<Joiner>().Single().Delimiter, type.GetFieldTitles());
    }

[AttributeUsage(AttributeTargets.Class)]
public sealed class Joiner : Attribute {
    public string Delimiter;

    /// <summary>Indicates that this class represents a delimited record. </summary>
    /// <param name="delimiter">The separator string used to split the fields of the record.</param>
    public Joiner(string delimiter) {
            this.Delimiter = delimiter;
    }
}

@FWest98
1. This is covered by the engine: use engine.GetFileHeader()
see https://github.com/MarcosMeli/FileHelpers/blob/master/FileHelpers/Engines/EngineBase.cs
2. DelimitedRecord has (now) a public accessible property Separator https://github.com/MarcosMeli/FileHelpers/commit/f46a39af4ff22c63e265bce8156bd304c2b878e4
=> type.GetCustomAttributes(true).OfType<DelimitedRecordAttribute>()
3. in older versions, you should be able to access this via DelimitedFileEngine(type).Options.Delimiter

so, no need for an additional attribute ;)

overall:
engine.GetFileHeader() seems to use field.FriendlyName from FieldBase, but I can't see how or if this can be invoked? Default is fieldName, else a part of the reflective field ... I don't understand that code atm. So perhaps @MarcosMeli or someone else might point it out ;) Perhaps it's much easier to add custom fieldTitles?!

I would really add BindingFlags.Public to

    static int GetOrder(this FieldOrderAttribute attribute)
    {
        // Hack cos FieldOrderAttribute.Order is internal (why?)
        var pi = typeof(FieldOrderAttribute)
            .GetProperty("Order",
                BindingFlags.GetProperty |
                BindingFlags.Instance |
                BindingFlags.NonPublic);

        return (int)pi.GetValue(attribute, null);
    }

What is FieldOrderAttribute stands for?

https://github.com/MarcosMeli/FileHelpers/blob/master/FileHelpers/Attributes/FieldOrderAttribute.cs

Thrown Error in FieldTitleAttribute

Given attribute as

    [FieldOrder(1), FieldTitle("Field1")]
    [FieldTrim(TrimMode.Both)]
    public String Field1;

    [FieldOrder(2), FieldTitle("Field2")]
    public Int32 Field2;

    [FieldOrder(3), FieldTitle("Field3")]
    public Int32 Field3;

    [FieldOrder(4), FieldTitle("Field4")]
    [FieldTrim(TrimMode.Both)]
    [FieldConverter(ConverterKind.Date, "dd/MM/yyyy")]
    public DateTime Field4;

    [FieldOrder(5), FieldTitle("Field5")]
    [FieldTrim(TrimMode.Both)]
    public String Field5;

    [FieldOrder(6), FieldTitle("Field6")]
    [FieldTrim(TrimMode.Both)]
    public String Field6;

Got Error as :

System.NullReferenceException was unhandled
HResult=-2147467261
Message=Object reference not set to an instance of an object.
Source=ConsoleApplicationBRDTest
StackTrace:
at FileHelpers.FileHelpersTypeExtensions.GetOrder(FieldOrderAttribute attribute) in C:\Users\T3328\documents\visual studio 2010\Projects\ConsoleApplicationBRDTest\ConsoleApplicationBRDTest\FileHelpersTypeExtensions.cs:line 67
at FileHelpers.FileHelpersTypeExtensions.b__5(<>f__AnonymousType02 <>h__TransparentIdentifier0) in C:\Users\T3328\documents\visual studio 2010\Projects\ConsoleApplicationBRDTest\ConsoleApplicationBRDTest\FileHelpersTypeExtensions.cs:line 40
at System.Linq.Enumerable.<>c__DisplayClass12
3.b__11(TSource x)
at System.Linq.Enumerable.<>c__DisplayClass123.<CombineSelectors>b__11(TSource x)
at System.Linq.Enumerable.WhereSelectArrayIterator
2.MoveNext()
at System.Linq.Buffer1..ctor(IEnumerable1 source)
at System.Linq.OrderedEnumerable1.<GetEnumerator>d__0.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator
2.MoveNext()
at System.String.Join(String separator, IEnumerable`1 values)
at FileHelpers.FileHelpersTypeExtensions.GetCsvHeader(Type type) in C:\Users\T3328\documents\visual studio 2010\Projects\ConsoleApplicationBRDTest\ConsoleApplicationBRDTest\FileHelpersTypeExtensions.cs:line 48
at ConsoleApplicationBRDTest.Program.Main(String[] args) in C:\Users\T3328\documents\visual studio 2010\Projects\ConsoleApplicationBRDTest\ConsoleApplicationBRDTest\Program.cs:line 102
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:

when returning line : return (int)pi.GetValue(attribute, null);

Will it be correct if I replace like this :

//return (int)pi.GetValue(attribute,null);

return attribute.Order;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.