为啥 Type.GetFields() 不返回基类中的支持字段?
Posted
技术标签:
【中文标题】为啥 Type.GetFields() 不返回基类中的支持字段?【英文标题】:Why doesn't Type.GetFields() return backing fields in a base class?为什么 Type.GetFields() 不返回基类中的支持字段? 【发布时间】:2012-03-01 09:24:49 【问题描述】:在 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。
【问题讨论】:
【参考方案1】:作为后备字段的字段对反射没有影响。支持字段的唯一相关属性是它们是私有的。
反射函数不返回基类的私有成员,即使您使用FlattenHierarchy
。您将需要手动遍历您的类层次结构,并要求每个类的私有字段。
我认为FlattenHierarchy
的编写目的是显示所有成员对您查看的类中的代码可见。因此,基成员可以被派生类中具有相同名称的成员隐藏/隐藏,而私有成员则根本不可见。
【讨论】:
FlattenHierarchy 具有以下注释 指定应返回层次结构上的公共和受保护静态成员。不返回继承类中的私有静态成员。静态成员包括字段、方法、事件和属性。不返回嵌套类型。它在这里提到了静态这个词,这让我觉得它不适用于非静态成员【参考方案2】:这是一个使用 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();
【讨论】:
"Cygon 的示例函数仅在类具有基类 != 对象时才检索基类的字段。" - 我不明白你想说什么。我用起始类型的字段初始化了我的List<FieldInfo>
,就像你做HashSet<FieldInfo>
一样,所以两个解决方案也将包含起始类型的字段。
否则,做得很好,尤其是你使用UnionWith()
,比我的数组扫描优雅得多。性能方面,HashSet
似乎没有多大作用,我尝试了 30 个字段在 3 个继承级别进行 1,000,000 次迭代,完成时间为 7157 毫秒(列表)和 7160 毫秒(哈希集)。
对不起,您是对的。它可能是一个具有这种限制的中间实现,我认为它是你的。我在上面的文字中删除了我的陈述。【参考方案3】:
感谢@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。
编辑:还要注意,这不会在继承链中进一步搜索类型。就我而言,我知道在调用该方法时我处于最派生的类型。
【讨论】:
以上是关于为啥 Type.GetFields() 不返回基类中的支持字段?的主要内容,如果未能解决你的问题,请参考以下文章
Apollo Graphql 自定义标量 JSON - 抱怨“TypeError:type.getFields 不是函数”