C#命令获取struct offset?

时间:2010-01-22 20:44:15

标签: c#

假设我有一个像这样的C#结构:

[StructLayout(LayoutKind.Explicit)]
struct IMAGE_DOS_HEADER {
    [FieldOffset(60)] public int e_lfanew;
}

现在假设我从文件中读取数据,如下所示:

byte[] data = new byte[4096];
FileStream f = new FileInfo(filename).Open(FileMode.Open, FileAccess.Read);
int n = f.Read(data, 0, 4096);

现在我想测试n以确保我已经读取了足够的字节来获取e_lfanew的值。有没有什么办法可以获得值60(FieldOffset)而无需重新输入?我正在寻找这样的东西:

if (n >= offsetof(IMAGE_DOS_HEADER.e_lfanew) + sizeof(int)) {
    ...
}

有没有这样的命令?在我的实际代码中,我必须进行其中几个测试,并且通过在结构中添加先前字段或通过从FieldOffset属性中复制值来手动输入数字似乎很乏味且容易出错。还有更好的方法吗?

3 个答案:

答案 0 :(得分:18)

使用Marshal.OffsetOf:

Marshal.OffsetOf(typeof(IMAGE_DOS_HEADER), "e_lfanew")

答案 1 :(得分:7)

是的,你可以使用反射来做到这一点。

FieldOffsetAttribute fieldOffset = 
    (FieldOffsetAttribute)typeof(IMAGE_DOS_HEADER)
        .GetField("e_lfanew")
        .GetCustomAttributes(
            typeof(FieldOffsetAttribute),
            true
        )[0];
Console.WriteLine(fieldOffset.Value);

你甚至可以把它变成一个很好的方法:

static int FieldOffset<T>(string fieldName) {
    if (typeof(T).IsValueType == false) {
        throw new ArgumentOutOfRangeException("T");
    }
    FieldInfo field = typeof(T).GetField(fieldName);
    if (field == null) {
        throw new ArgumentOutOfRangeException("fieldName");
    }
    object[] attributes = field.GetCustomAttributes(
        typeof(FieldOffsetAttribute),
        true
    );
    if (attributes.Length == 0) {
        throw new ArgumentException();
    }
    FieldOffsetAttribute fieldOffset = (FieldOffsetAttribute)attributes[0];
    return fieldOffset.Value;
}

用法:

Console.WriteLine(FieldOffset<IMAGE_DOS_HEADER>("e_lfanew"));

答案 2 :(得分:7)

嗯,你已经在结构声明中使用了一个幻数。不妨这样做:

private const int LfaNewOffset = 60;

[StructLayout(LayoutKind.Explicit)]
struct IMAGE_DOS_HEADER {
    [FieldOffset(LfaNewOffset)] public int e_lfanew;
}
...
if (n >= LfaNewOffset + sizeof(int)) {
    ...
}