【问题标题】:Reflection in combination with marshal not working反射结合元帅不起作用
【发布时间】:2015-10-12 05:11:31
【问题描述】:

我遇到了结合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 类的文档中,微软说:“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);
    }
}

【问题讨论】:

    标签: .net dynamic reflection struct marshalling


    【解决方案1】:

    如果有人对我的解决方案感兴趣:)

    正如(过时的)UnmanagedMarshal 类的文档中所述,我必须使用 CustomAttributeBuilder 传递“MarshalAs”属性。

    诀窍是使用 MarshalAsAttribute 类而不是自己编写的类(参见下面的代码)。由于有关此主题的文档很差,我在找到解决方案时遇到了一些麻烦。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-30
      • 1970-01-01
      • 2019-12-20
      相关资源
      最近更新 更多