Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic Class Builder #424

Open
FlemmingOstergaard opened this issue May 29, 2022 · 0 comments
Open

Dynamic Class Builder #424

FlemmingOstergaard opened this issue May 29, 2022 · 0 comments

Comments

@FlemmingOstergaard
Copy link

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);
        }
    }
}

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant