C# Reflection: How to Emit a class

核能气质少年 提交于 2020-01-14 03:37:14

问题


I have a class, ReferenceObject, that I want Emitted into the dll I create. How do I do this without writing every method with Emit? I basically want this class added to the dll I generate.

Here is the class:

public class ReferenceObject
{
    private readonly int value;

    public ReferenceObject(int pValue)
    {
        value = pValue;
    }

    public override string ToString()
    {
        return value.ToString();
    }

    public int Value()
    {
        return value;
    }

    public int ID()
    {
        return value;
    }

    #region == Operator

    public static bool operator ==(int objLeft, ReferenceObject objRight)
    {
        return objLeft == objRight.value;
    }

    public static bool operator ==(ReferenceObject objLeft, int objRight)
    {
        return objLeft.value == objRight;
    }

    public static bool operator ==(string objLeft, ReferenceObject objRight)
    {
        return objLeft == objRight.value.ToString();
    }

    public static bool operator ==(ReferenceObject objLeft, string objRight)
    {
        return objLeft.value.ToString() == objRight;
    }

    #endregion

    #region != Operator

    public static bool operator !=(int objLeft, ReferenceObject objRight)
    {
        return objLeft != objRight.value;
    }

    public static bool operator !=(ReferenceObject objLeft, int objRight)
    {
        return objLeft.value != objRight;
    }

    public static bool operator !=(string objLeft, ReferenceObject objRight)
    {
        return objLeft != objRight.value.ToString();
    }

    public static bool operator !=(ReferenceObject objLeft, string objRight)
    {
        return objLeft.value.ToString() != objRight;
    }

    #endregion

    public override bool Equals(object obj)
    {
        if ((obj is ReferenceObject))
            return value == ((ReferenceObject)obj).value;

        if ((obj is int))
            return value == (int)obj;

        if ((obj is string))
            return value.ToString() == (string)obj;

        return false;
    }

    public override int GetHashCode()
    {
        return value;
    }
}

And here is the code I use to generate the .dll

AppDomain domain = AppDomain.CurrentDomain;

AssemblyName aName = new AssemblyName("DynamicEnums");
AssemblyBuilder ab = domain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Save);

ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");

ConstructorInfo referenceObjectConstructor = typeof(ReferenceObject).GetConstructor(new[] { typeof(int) });

List<Type> types = new List<Type>();

foreach(ReferenceType rt in GetTypes())
{
    TypeBuilder tb = mb.DefineType(rt.Name, TypeAttributes.Public | TypeAttributes.BeforeFieldInit);

    ConstructorBuilder staticConstructorBuilder = tb.DefineConstructor(MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, Type.EmptyTypes);
    ILGenerator staticConstructorILGenerator = staticConstructorBuilder.GetILGenerator();

    foreach (Reference r in GetReferences(rt.ID))
    {
        name = NameFix(r.Name);

        // Create a public, static, readonly field to store the
        // named ReferenceObject.
        FieldBuilder referenceObjectField = tb.DefineField(name, typeof(ReferenceObject), FieldAttributes.Static | FieldAttributes.Public | FieldAttributes.InitOnly);

        // Add code to the static constructor to populate the
        // ReferenceObject field:

        // Load the ReferenceObject's ID value onto the stack as a
        // literal 4-byte integer (Int32).
        staticConstructorILGenerator.Emit(OpCodes.Ldc_I4, r.ID);

        // Create a reference to a new ReferenceObject on the stack
        // by calling the ReferenceObject(int32 pValue) reference
        // we created earlier.
        staticConstructorILGenerator.Emit(OpCodes.Newobj, referenceObjectConstructor);

        // Store the ReferenceObject reference to the static
        // ReferenceObject field.
        staticConstructorILGenerator.Emit(OpCodes.Stsfld, referenceObjectField);
    }
    staticConstructorILGenerator.Emit(OpCodes.Ret);

    types.Add(tb.CreateType());
}

ab.Save(aName.Name + ".dll");

回答1:


Take a look at the Reflection.Emit add-in for Reflector:

You can download Reflector here:
http://www.reflector.net/

And here is a link to the add-in:
http://reflectoraddins.codeplex.com/wikipage?title=ReflectionEmitLanguage&referringTitle=Home

EDIT

You might also want to take a look at this article:
http://www.codeproject.com/KB/dotnet/Creating_Dynamic_Types.aspx




回答2:


In response to comment.

Why not just use CodeDom then, or just use or write an 'offline' code generator? Reflection.Emit is only needed when you want to create types at runtime, else it is pretty much overkill.

See here for an example of what I did years ago.



来源:https://stackoverflow.com/questions/7769287/c-sharp-reflection-how-to-emit-a-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!