Skip to content

Dynamic Class Builder #424

Description

@FlemmingOstergaard

I noticed that FileHelpers Dynamic is not implemented under NET 6.
I have writte a ClassBuilder, that works very well with the existing Delimited/Fixed engive:
The code is here, feel free to use it.
It uses reflection to build the class from a simple list of fields info.

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using FileHelpers;

namespace KBFileHelpersDynamic {
public class Field {
public string FieldName;
public Type FieldType;
public int FieldFixedLength;
public QuoteMode QM = QuoteMode.AlwaysQuoted;
public bool Quoted;
}

public static class FileHelpersTypeBuilder {

    enum FileType { Delimited, Fixed };

    public static Type BuildClassDelimited(List<Field> _fields, string _delim = ";", string _cult = "") {
        return BuildClass(FileType.Delimited, _fields, _delim, _cult);
    }
    public static Type BuildClassFixed(List<Field> _fields, string _cult = "") {
        return BuildClass(FileType.Fixed, _fields, _cult);
    }

    private static Type BuildClass(FileType _filetype, List<Field> _fields, string _delim = ";", string _cult = "") {
        TypeBuilder tb = GetTypeBuilder();
        ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);

        if(_cult == "")
            _cult = System.Globalization.CultureInfo.CurrentCulture.ToString();

        // Ignore empty lines
        Type[] attrCtorParams = new Type[0];
        var attrCtorInfo = typeof(IgnoreEmptyLinesAttribute).GetConstructor(attrCtorParams);
        CustomAttributeBuilder attrBuilder = new CustomAttributeBuilder(attrCtorInfo, new object[0]);
        tb.SetCustomAttribute(attrBuilder);

        if(_filetype == FileType.Delimited) {
            // Set Type Delimited and delimiter char
            attrCtorParams = new Type[] { typeof(string), typeof(string) };
            attrCtorInfo = typeof(DelimitedRecordAttribute).GetConstructor(attrCtorParams);
            attrBuilder = new CustomAttributeBuilder(attrCtorInfo, new object[] { _delim, _cult });
            tb.SetCustomAttribute(attrBuilder);
        }
        else {
            // Set Type Fixed record length
            attrCtorParams = new Type[] { typeof(FixedMode), typeof(string) };
            attrCtorInfo = typeof(FixedLengthRecordAttribute).GetConstructor(attrCtorParams);
            attrBuilder = new CustomAttributeBuilder(attrCtorInfo, new object[] { FixedMode.ExactLength, _cult });
            tb.SetCustomAttribute(attrBuilder);
        }

        // NOTE: assuming your list contains Field objects with fields FieldName(string) and FieldType(Type)
        foreach(var field in _fields)
            CreateProperty(_filetype, tb, field);

        return tb.CreateType();
    }

    private static TypeBuilder GetTypeBuilder() {
        var typeSignature = "MyDynamicType";
        var an = new AssemblyName(typeSignature);
        AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
        TypeBuilder tb = moduleBuilder.DefineType(typeSignature,
                TypeAttributes.Public |
                TypeAttributes.Class |
                TypeAttributes.AutoClass |
                TypeAttributes.AnsiClass |
                TypeAttributes.BeforeFieldInit |
                TypeAttributes.AutoLayout,
                null);
        return tb;
    }

    private static void CreateProperty(FileType _ftype, TypeBuilder tb, Field _field) {
        string propertyName = _field.FieldName;
        Type propertyType = _field.FieldType;
        FieldBuilder fieldBuilder = tb.DefineField(propertyName, propertyType, FieldAttributes.Public);

        if(_ftype == FileType.Fixed) {
            Type[] attrCtorParams = new Type[] { typeof(int) };
            var attrCtorInfo = typeof(FieldFixedLengthAttribute).GetConstructor(attrCtorParams);
            var attrBuilder = new CustomAttributeBuilder(attrCtorInfo, new object[] { _field.FieldFixedLength });
            fieldBuilder.SetCustomAttribute(attrBuilder);
        }

        if(_ftype == FileType.Delimited) {
            Type[] attrCtorParams = new Type[0];
            var attrCtorInfo = typeof(FieldOptionalAttribute).GetConstructor(attrCtorParams);
            var attrBuilder = new CustomAttributeBuilder(attrCtorInfo, new object[0]);
            fieldBuilder.SetCustomAttribute(attrBuilder);
        }
        if(_ftype == FileType.Delimited && _field.Quoted) {             // Only if quoted at all
            Type[] attrCtorParams = new Type[] { typeof(char), typeof(QuoteMode), typeof(MultilineMode) };
            var attrCtorInfo = typeof(FieldQuotedAttribute).GetConstructor(attrCtorParams);
            var attrBuilder = new CustomAttributeBuilder(attrCtorInfo, new object[] { '"', _field.QM, MultilineMode.AllowForBoth });
            fieldBuilder.SetCustomAttribute(attrBuilder);
        }
    }
}

}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions