结合元帅的反思不工作
Reflection in combination with marshal not working
我在反射与 MarshalAs
属性结合时遇到问题。我想在运行时动态创建具有反射的结构。这些结构可能包含需要编组的数组。 Field.SetMarshal()
方法自 .NET 2.0 以来已过时,我找不到替代方法。
我在运行时构建的结构示例:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct Example
{
public int var1;
public float var2;
public byte var3;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public int[] var4;
}
使用反射构建结构的代码:
TypeBuilder tb = mb.DefineType(pT.name, // Name of struct type
TypeAttributes.Public | // Public scope
TypeAttributes.SequentialLayout | // Sequential layout
TypeAttributes.AnsiClass, // Ansi Charset
typeof(ValueType), // Value type
PackingSize.Size1); // Packing size is 1 byte
// Add public fields to new struct type
foreach (parsedField pF in pT.fields)
{
FieldBuilder fb = tb.DefineField(pF.name, pF.type, FieldAttributes.Public);
// Add Marshall information to arrays
if (fb.FieldType.IsArray)
{
// ADD MARSHAL INFORMATION HERE
}
}
在过时的 UnmanagedMarshal class 的文档中,Microsoft 说:"Emit the MarshalAs custom attribute instead"
好吧,我尝试制作一个 CustomAttribute
("MarshalAs") 并用 Field.SetCustomAttribute()
添加它,但这也不起作用 - 结构的大小总是错误的。
[AttributeUsage(AttributeTargets.Field)]
public class MarshalAs : System.Attribute
{
public UnmanagedType type;
public int SizeConst;
public MarshalAs(UnmanagedType type, int SizeConst)
{
this.type = type;
this.SizeConst = SizeConst;
}
}
...
TypeBuilder tb = mb.DefineType(pT.name, // Name of struct type
TypeAttributes.Public | // Public scope
TypeAttributes.SequentialLayout | // Sequential layout
TypeAttributes.AnsiClass, // Ansi Charset
typeof(ValueType), // Value type
PackingSize.Size1); // Packing size is 1 byte
// Add public fields to new struct type
foreach (parsedField pF in pT.fields)
{
FieldBuilder fb = tb.DefineField(pF.name, pF.type, FieldAttributes.Public);
// Add Marshall information to arrays
if (fb.FieldType.IsArray)
{
ConstructorInfo ci = typeof(MarshalAs).GetConstructor(new Type[] { typeof(UnmanagedType), typeof(int) });
CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(ci, new object[] { UnmanagedType.ByValArray, 8 });
fb.SetCustomAttribute(customBuilder);
}
}
如果有人对我的解决方案感兴趣:)
如(过时的)UnmanagedMarshal class 的文档中所述,我必须使用 CustomAttributeBuilder 传递 "MarshalAs" 属性。
诀窍是使用 MarshalAsAttribute class 而不是自己编写的(参见下面的代码)。由于有关此主题的文档很差,我在找到解决方案时遇到了一些麻烦。
FieldBuilder fb = tb.DefineField(pF.name, pF.type, FieldAttributes.Public);
// Add Marshall information to arrays
// The "MarshallAs" attribute has to be passed with a CustomAttributeBuilder
if (fb.FieldType.IsArray)
{
// First we define a list of types of the arguments of the "MarshalAs" attribute constructor
Type[] argTypes = new Type[] { typeof(UnmanagedType) };
// Now we create a list of concrete constructor arguments for the "MarshalAs" attribute constructor
object[] args = new object[] { UnmanagedType.ByValArray };
// We need the field information of "SizeConst" of the MarshalAs attribute
FieldInfo[] sizeConstField = new FieldInfo[] { typeof(MarshalAsAttribute).GetField("SizeConst") };
// We create the value for the field "SizeConst"
object[] sizeConstValue = new object[] { pF.arrSize };
// Now we retrieve the constructor of "MarshalAs" attribute that matches specified constructor argument types
ConstructorInfo ci = typeof(MarshalAsAttribute).GetConstructor(argTypes);
// Create builder for "MarshalAs" attribute
CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(ci, args, sizeConstField, sizeConstValue);
// Set builder for MarshalAs attribute
fb.SetCustomAttribute(customBuilder);
}
我在反射与 MarshalAs
属性结合时遇到问题。我想在运行时动态创建具有反射的结构。这些结构可能包含需要编组的数组。 Field.SetMarshal()
方法自 .NET 2.0 以来已过时,我找不到替代方法。
我在运行时构建的结构示例:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct Example
{
public int var1;
public float var2;
public byte var3;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public int[] var4;
}
使用反射构建结构的代码:
TypeBuilder tb = mb.DefineType(pT.name, // Name of struct type
TypeAttributes.Public | // Public scope
TypeAttributes.SequentialLayout | // Sequential layout
TypeAttributes.AnsiClass, // Ansi Charset
typeof(ValueType), // Value type
PackingSize.Size1); // Packing size is 1 byte
// Add public fields to new struct type
foreach (parsedField pF in pT.fields)
{
FieldBuilder fb = tb.DefineField(pF.name, pF.type, FieldAttributes.Public);
// Add Marshall information to arrays
if (fb.FieldType.IsArray)
{
// ADD MARSHAL INFORMATION HERE
}
}
在过时的 UnmanagedMarshal class 的文档中,Microsoft 说:"Emit the MarshalAs custom attribute instead"
好吧,我尝试制作一个 CustomAttribute
("MarshalAs") 并用 Field.SetCustomAttribute()
添加它,但这也不起作用 - 结构的大小总是错误的。
[AttributeUsage(AttributeTargets.Field)]
public class MarshalAs : System.Attribute
{
public UnmanagedType type;
public int SizeConst;
public MarshalAs(UnmanagedType type, int SizeConst)
{
this.type = type;
this.SizeConst = SizeConst;
}
}
...
TypeBuilder tb = mb.DefineType(pT.name, // Name of struct type
TypeAttributes.Public | // Public scope
TypeAttributes.SequentialLayout | // Sequential layout
TypeAttributes.AnsiClass, // Ansi Charset
typeof(ValueType), // Value type
PackingSize.Size1); // Packing size is 1 byte
// Add public fields to new struct type
foreach (parsedField pF in pT.fields)
{
FieldBuilder fb = tb.DefineField(pF.name, pF.type, FieldAttributes.Public);
// Add Marshall information to arrays
if (fb.FieldType.IsArray)
{
ConstructorInfo ci = typeof(MarshalAs).GetConstructor(new Type[] { typeof(UnmanagedType), typeof(int) });
CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(ci, new object[] { UnmanagedType.ByValArray, 8 });
fb.SetCustomAttribute(customBuilder);
}
}
如果有人对我的解决方案感兴趣:)
如(过时的)UnmanagedMarshal class 的文档中所述,我必须使用 CustomAttributeBuilder 传递 "MarshalAs" 属性。
诀窍是使用 MarshalAsAttribute class 而不是自己编写的(参见下面的代码)。由于有关此主题的文档很差,我在找到解决方案时遇到了一些麻烦。
FieldBuilder fb = tb.DefineField(pF.name, pF.type, FieldAttributes.Public);
// Add Marshall information to arrays
// The "MarshallAs" attribute has to be passed with a CustomAttributeBuilder
if (fb.FieldType.IsArray)
{
// First we define a list of types of the arguments of the "MarshalAs" attribute constructor
Type[] argTypes = new Type[] { typeof(UnmanagedType) };
// Now we create a list of concrete constructor arguments for the "MarshalAs" attribute constructor
object[] args = new object[] { UnmanagedType.ByValArray };
// We need the field information of "SizeConst" of the MarshalAs attribute
FieldInfo[] sizeConstField = new FieldInfo[] { typeof(MarshalAsAttribute).GetField("SizeConst") };
// We create the value for the field "SizeConst"
object[] sizeConstValue = new object[] { pF.arrSize };
// Now we retrieve the constructor of "MarshalAs" attribute that matches specified constructor argument types
ConstructorInfo ci = typeof(MarshalAsAttribute).GetConstructor(argTypes);
// Create builder for "MarshalAs" attribute
CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(ci, args, sizeConstField, sizeConstValue);
// Set builder for MarshalAs attribute
fb.SetCustomAttribute(customBuilder);
}