为什么 Type.GetFields() 不返回基类中的支持字段?
在 C# 中,如果将 Type.GetFields()
与表示派生类的类型一起使用,它将返回 a) 派生类中所有显式声明的字段,b) 派生类中自动属性的所有支持字段派生类和 c) 基类中所有显式声明的字段。
为什么基类中自动属性的 d) 支持字段缺失?
示例:
public class Base {
public int Foo { get; set; }
}
public class Derived : Base {
public int Bar { get; set; }
}
class Program {
static void Main(string[] args) {
FieldInfo[] fieldInfos = typeof(Derived).GetFields(
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.FlattenHierarchy
);
foreach(FieldInfo fieldInfo in fieldInfos) {
Console.WriteLine(fieldInfo.Name);
}
}
}
这将仅显示 Bar 的背景字段,而不显示 Foo。
In C#, if you use Type.GetFields()
with a type representing a derived class, it will return a) all explicitly declared fields in the derived class, b) all backing fields of automatic properties in the derived class and c) all explicitly declared fields in the base class.
Why are the d) backing fields of automatic properties in the base class missing?
Example:
public class Base {
public int Foo { get; set; }
}
public class Derived : Base {
public int Bar { get; set; }
}
class Program {
static void Main(string[] args) {
FieldInfo[] fieldInfos = typeof(Derived).GetFields(
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.FlattenHierarchy
);
foreach(FieldInfo fieldInfo in fieldInfos) {
Console.WriteLine(fieldInfo.Name);
}
}
}
This will show only the backing field of Bar, not Foo.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

发布评论
评论(3)
这是使用 HashSet 的修订版本:
public static FieldInfo[] GetFieldInfosIncludingBaseClasses(Type type, BindingFlags bindingFlags)
{
FieldInfo[] fieldInfos = type.GetFields(bindingFlags);
// If this class doesn't have a base, don't waste any time
if (type.BaseType == typeof(object))
{
return fieldInfos;
}
else
{ // Otherwise, collect all types up to the furthest base class
var currentType = type;
var fieldComparer = new FieldInfoComparer();
var fieldInfoList = new HashSet<FieldInfo>(fieldInfos, fieldComparer);
while (currentType != typeof(object))
{
fieldInfos = currentType.GetFields(bindingFlags);
fieldInfoList.UnionWith(fieldInfos);
currentType = currentType.BaseType;
}
return fieldInfoList.ToArray();
}
}
private class FieldInfoComparer : IEqualityComparer<FieldInfo>
{
public bool Equals(FieldInfo x, FieldInfo y)
{
return x.DeclaringType == y.DeclaringType && x.Name == y.Name;
}
public int GetHashCode(FieldInfo obj)
{
return obj.Name.GetHashCode() ^ obj.DeclaringType.GetHashCode();
}
}
感谢@CodeInChaos 快速而完整的回答!
如果其他人偶然发现了这个问题,这里有一个快速解决方法,可以沿着字段一直到最远的基类。
/// <summary>
/// Returns all the fields of a type, working around the fact that reflection
/// does not return private fields in any other part of the hierarchy than
/// the exact class GetFields() is called on.
/// </summary>
/// <param name="type">Type whose fields will be returned</param>
/// <param name="bindingFlags">Binding flags to use when querying the fields</param>
/// <returns>All of the type's fields, including its base types</returns>
public static FieldInfo[] GetFieldInfosIncludingBaseClasses(
Type type, BindingFlags bindingFlags
) {
FieldInfo[] fieldInfos = type.GetFields(bindingFlags);
// If this class doesn't have a base, don't waste any time
if(type.BaseType == typeof(object)) {
return fieldInfos;
} else { // Otherwise, collect all types up to the furthest base class
var fieldInfoList = new List<FieldInfo>(fieldInfos);
while(type.BaseType != typeof(object)) {
type = type.BaseType;
fieldInfos = type.GetFields(bindingFlags);
// Look for fields we do not have listed yet and merge them into the main list
for(int index = 0; index < fieldInfos.Length; ++index) {
bool found = false;
for(int searchIndex = 0; searchIndex < fieldInfoList.Count; ++searchIndex) {
bool match =
(fieldInfoList[searchIndex].DeclaringType == fieldInfos[index].DeclaringType) &&
(fieldInfoList[searchIndex].Name == fieldInfos[index].Name);
if(match) {
found = true;
break;
}
}
if(!found) {
fieldInfoList.Add(fieldInfos[index]);
}
}
}
return fieldInfoList.ToArray();
}
}
请注意,我正在手动比较嵌套 for 循环中的字段。如果您有深度嵌套的类或非常大的类,请随意使用 HashSet<> 。反而。
编辑:另请注意,这不会在继承链中进一步搜索类型。就我而言,我知道在调用该方法时我处于最派生的类型。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
作为支持场的场对反射没有影响。支持字段的唯一相关属性是它们是私有的。
即使您使用
FlattenHierarchy
,反射函数也不会返回基类的私有成员。您将需要手动遍历类层次结构并要求每个类层次结构中的私有字段。我认为
FlattenHierarchy
的编写目的是显示您所查看的类中的代码可见的所有成员。因此,基类成员可以被派生类中具有相同名称的成员隐藏/遮蔽,而私有成员根本不可见。A field being a backing field has no influence on reflection. The only relevant property of backing fields is that they are private.
Reflection functions don't return private members of base classes, even if you use
FlattenHierarchy
. You will need to loop manually over your class hierarchy and ask for private fields on each one.I think
FlattenHierarchy
is written with the intent to show all members visible to code in the class you look at. So base members can be hidden/shadowed by members with the same name in a more derived class and private members are not visible at all.