gpt4 book ai didi

c# - GetSerializableMembers (FormatterServices) 返回同一个字段两次!为什么?

转载 作者:太空狗 更新时间:2023-10-29 19:47:08 25 4
gpt4 key购买 nike

FormatterServices.GetSerializableMembers为派生类型返回两次 protected 字段和内部字段。一次作为 SerializationFieldInfo 的实例,一次作为 RtFieldInfo

我觉得这很令人困惑!谁能帮我理解为什么 Microsoft 决定以这种方式实现它?

我写了一个示例程序来重现我的问题:

class Program
{
[Serializable]
public class BaseA
{
private int privateField;
}

[Serializable]
public class DerivedA : BaseA { }

[Serializable]
public class BaseB
{
protected int protectedField;
}

[Serializable]
public class DerivedB : BaseB { }

static void Main(string[] args)
{
Program.PrintMemberInfo(typeof(DerivedA));
Program.PrintMemberInfo(typeof(DerivedB));
Console.ReadKey();
}

static void PrintMemberInfo(Type t)
{
Console.WriteLine(t.Name);

foreach (var mbr in FormatterServices.GetSerializableMembers(t))
{
Console.WriteLine(" {0} ({1})", mbr.Name, mbr.MetadataToken);
}

Console.WriteLine();
}
}

我希望 privateFieldprotectedField 各报告一次。然而,这是运行程序时的实际输出:

DerivedA  BaseA+privateField (67108865)DerivedB  protectedField (67108866)  BaseB+protectedField (67108866)

如您所见,protectedField 出现了两次,名称不同但元数据标记相同,因此它确实是同一个字段。

谁能解释一下为什么?

最佳答案

这似乎与 FormatterServices 关系不大,但与反射的工作原理以及 FormatterServices 如何使用它有关。对于与 BindingFlags.NonPublic 一起使用时的 Type.GetFields 方法(参见:http://msdn.microsoft.com/en-us/library/6ztex2dc.aspx):“仅返回基类上的 protected 字段和内部字段;基类上的私有(private)字段类(class)不会返回。”

完全取消任何检查,并根据您的示例量身定制,FormatterServices 获取字段的基本操作是:

    static IEnumerable<FieldInfo> GetSerializableFields(Type type, Func<Type, IEnumerable<FieldInfo>> andNext)
{
return
(type.IsInterface || type == typeof(object))
? new FieldInfo[0]
: type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(f => (f.Attributes & FieldAttributes.NotSerialized) != FieldAttributes.NotSerialized)
.Concat(andNext(type));
}

static void PrintMemberInfo(Type t)
{
Console.WriteLine(t.Name);

Func<Type, IEnumerable<FieldInfo>> andNext = null;
andNext = tp => GetSerializableFields(tp.BaseType, andNext);
var fields = GetSerializableFields(t, tp => new FieldInfo[0]).ToArray();
var base_fields = GetSerializableFields(t.BaseType, andNext).ToArray();

var counter = 0;
foreach (var f in fields.Concat(base_fields))
{
Console.WriteLine(
"{0} Reflected: {1} - Declaring: {2} - Field: {3} ({4})",
(counter++) + 1, f.ReflectedType.Name, f.DeclaringType.Name, f.Name, f.MetadataToken);
}
Console.WriteLine();
}
}

它为您的示例类生成以下输出:

DerivedA
1 Reflected: BaseA - Declaring: BaseA - Field: privateField (67108865)

DerivedB
1 Reflected: DerivedB - Declaring: BaseB - Field: protectedField (67108866)
2 Reflected: BaseB - Declaring: BaseB - Field: protectedField (67108866)

并且 FormatterServices 根本不会通过检查是否多次包含来自同一声明类型的同一字段来过滤其结果。鉴于 FormatterServices 的实现方式(对类型的可序列化基类型执行检查),他们可能应该做一些类似 filter by ReflectedType == DeclaringType 的事情:

希望这对您有所帮助。

关于c# - GetSerializableMembers (FormatterServices) 返回同一个字段两次!为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15166360/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com