Type.GetFields()不按特定顺序返回字段,但我想按声明顺序对它们进行排序。我怎样才能做到这一点?我没有在FieldInfo中看到'index'属性或任何具有类似功能的东西。
动机:我想实现类似于this answer中的位域解决方案,但正如第二条评论所述,订单无法保证。
编辑:澄清 - 我不想创建此代码来依赖此排序。我想创建这个代码来解析已经有一定排序的现有二进制数据。
编辑2(回答后):我选择了一个完全回答问题的答案,并且在我的测试中正常运行,但是作为旁注,位域解决方案存在问题:< / p>
从位字段读取值时,您会得到一个无符号整数(某个大小),但是根据您在运行时获得的实际字段类型(byte,bool,int),您无法正确转换它。 FieldInfo。您可以使用运行时显式条件(if type.Equals(typeof(bool))
等)来完成它,但这有点难看。
我最终使用了C ++ / CLI,这使得这更加简单。
答案 0 :(得分:5)
您可以编写声明订单的自定义属性。然后,对于每个字段,查找该属性。使用值进行排序。
这不会是自动的,但这将是一种非常确定的方式。
使用示例:
[Index(0)]
private int myField;
[Index(1)]
private int myOtherField;
答案 1 :(得分:2)
您可以向属性
添加位置信息[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public class BitfieldAttribute : Attribute
{
public BitfieldAttribute(int position, int length)
{
this.Position = position;
this.Length = length;
}
public int Position { get; private set; }
public int Length { get; private set; }
}
然后你就可以通过像这样的字段进行迭代了
foreach (FieldInfo fld in type.GetFields().OrderBy(f => f.Position)) {
...
}
此属性将像这样使用
struct PESHeader
{
[Bitfield(0, 2)]
public uint reserved;
[Bitfield(1, 2)]
public uint scrambling_control;
[Bitfield(2, 1)]
public uint priority;
[Bitfield(3, 1)]
public uint data_alignment_indicator;
[Bitfield(4, 1)]
public uint copyright;
[Bitfield(5, 1)]
public uint original_or_copy;
}
与字母顺序相比,优势在于您可以控制稍后添加的新字段的位置,从而避免现有字段的位置发生变化。
答案 2 :(得分:1)
您可以像这样扩展BitFieldLength属性:
sealed class BitfieldLengthAttribute : Attribute
{
uint index;
uint length;
public BitfieldLengthAttribute(uint index, uint length)
{
this.index = index;
this.length = length;
}
public uint Index { get { return index; } }
public uint Length { get { return length; } }
}
然后手动为所有字段添加索引,检索列表中的类型并对属性索引上的列表进行排序。
答案 3 :(得分:0)
您可以使用Linq来对象并编写如下代码:
var fields = type.GetFields().OrderBy(f => f.Name).ToArray();
答案 4 :(得分:0)
在此link它表示按MetadataToken排序以获得减速顺序。 这意味着:
IEnumerable<FieldInfo> fields = t.GetFields().OrderBy(f=>f.MetadataToken);
我真的不明白它的工作原理,但现在它对我来说很好。