我正在通过反射动态创建一个 C# 结构,当我在调试器中检查该结构的类型时,我注意到 StructLayoutAttribute.Pack默认为 8。我想将 Pack 设置为 1。
本质上,我想通过反射来完成将此属性添加到结构声明中可以完成的操作:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
我试过在创建类型后使用反射,但由于 StructLayoutAttribute 属性没有 Setter,它会抛出异常。
我的直觉是它需要在调用 ModuleBuilder.DefineType 时发生(我当前正在设置 LayoutKind 等),但我没有看到任何明显的对应 TypeAttribute .
感谢任何指点。此处类的完整代码:
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;
}
}
}
最佳答案
看起来再添加一个参数可以让您指定包装尺寸:
来自 http://msdn.microsoft.com/en-us/library/eyzw8bhy.aspx :
public TypeBuilder DefineType(
string name,
TypeAttributes attr,
Type parent,
PackingSize packsize
)
关于C# 如何通过反射设置 StructLayoutAttribute.Pack?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16673378/