C# 如何通过反射设置 StructLayoutAttribute.Pack? [英] C# How to set StructLayoutAttribute.Pack via Reflection?

查看:145
本文介绍了C# 如何通过反射设置 StructLayoutAttribute.Pack?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我通过反射动态创建 C# 结构,当我在调试器中检查结构的类型时,我注意到 StructLayoutAttribute.Pack 默认为 8.我想将 Pack 设置为 1.

I am creating a C# struct dynamically via reflection, and when I examine the struct's Type in my debugger I note that the StructLayoutAttribute.Pack is defaulting to 8. I would like to set the Pack to 1.

本质上,我想通过反射来做一些可以通过将这个属性添加到结构声明中的事情:

Essentially, I would like to do via reflection what can be done by adding this attribute to the declaration of a struct:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]

我在类型创建后尝试使用反射,但由于 StructLayoutAttribute 属性没有 Setter,它会引发异常.

I have tried using reflection after the type is created, but since the StructLayoutAttribute property has no Setter, it throws an exception.

我的预感是它需要在对 ModuleBuilder.DefineType 的调用中发生(我目前正在设置 LayoutKind 等),但我没有看到任何明显的对应 TypeAttribute.

My hunch is that it needs to happen in the call to ModuleBuilder.DefineType (where I am currently setting the LayoutKind, etc.), but I don't see any obvious corresponding TypeAttribute.

任何指针表示赞赏.该类的完整代码在这里:

Any pointers appreciated. Complete code for the class here:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;

namespace AcmeCo.Serializable
{
    public class DynamicSimStructBuilder
    {

        private static Type structType;

        public static object GetStructInstance() {
            object ptInstance = Activator.CreateInstance(GetStruct(), new object[] { });
            return ptInstance;
        }

        public static Type GetStruct() {

            if (structType != null) {
               return structType; 
            }

            AppDomain myDomain = AppDomain.CurrentDomain;
            AssemblyName myAsmName = new AssemblyName("MyDynamicAssembly");

            AssemblyBuilder myAsmBuilder =
               myDomain.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.RunAndSave);

            ModuleBuilder structModule = myAsmBuilder.DefineDynamicModule("StructModule", "MyDynamicAssembly.dll");

            TypeBuilder structTypeBld = structModule.DefineType("AcmeCo.ThirdPartyAPIWrapper.DyanmicStruct", TypeAttributes.Public |
                TypeAttributes.Sealed | TypeAttributes.SequentialLayout | 
                TypeAttributes.Serializable | TypeAttributes.AnsiClass, typeof(ValueType));

            // use a set of variables defined in an XML file to create Fields on the struct
            ThirdPartyAPIVariableCollection collection = ThirdPartyAPIVariableCollection.Deserialize();
            foreach (ThirdPartyAPIVariable variable in collection.ThirdPartyAPIVariables)
            {
                FieldBuilder field = structTypeBld.DefineField(variable.Name, Type.GetType(variable.SystemDataType, true) , FieldAttributes.Public);
            }

            // Base class and base class constructor.
            Type objType = Type.GetType("System.Object");
            ConstructorInfo objCtor = objType.GetConstructor(new Type[] { });

            Type[] ctorParams = { };

            ConstructorBuilder pointCtor =
               structTypeBld.DefineConstructor(MethodAttributes.Public,
                                              CallingConventions.Standard, ctorParams);
            ILGenerator ctorIL = pointCtor.GetILGenerator();

            // Build the constructor. Begin by invoking the base class
            // constructor. The zero-index parameter of the constructor
            // is the new instance. Store the values of the fields.
            ctorIL.Emit(OpCodes.Ldarg_0);
            ctorIL.Emit(OpCodes.Call, objCtor);
            ctorIL.Emit(OpCodes.Ret);


            // Create the type, and then create an instance of the type 
            // (or not, doesn't hurt to comment the CreateInstance line out...)
            Type ptType = structTypeBld.CreateType();

            object ptInstance = Activator.CreateInstance(ptType, new object[] { });

            DynamicSimStructBuilder.structType = ptType;
            int sizeOfNewData = System.Runtime.InteropServices.Marshal.SizeOf(ptType);
            Console.WriteLine("New type is: " + sizeOfNewData);

            // save the newly created type to a DLL for use later
            // (or not, doesn't hurt to comment the next line out...)
            myAsmBuilder.Save("MyDynamicAssembly.dll");

            return ptType;
        }
    }
}

推荐答案

好像再增加一个参数可以让你指定包装尺寸:

Looks like adding one more parameter lets you specify the packing size:

来自 http://msdn.microsoft.com/en-us/library/eyzw8bhy.aspx:

public TypeBuilder DefineType(
    string name,
    TypeAttributes attr,
    Type parent,
    PackingSize packsize
)

这篇关于C# 如何通过反射设置 StructLayoutAttribute.Pack?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆