gpt4 book ai didi

c# - 为什么 GetProperties 两次列出 protected 属性(在通用基类中声明)?

转载 作者:可可西里 更新时间:2023-11-01 09:11:48 24 4
gpt4 key购买 nike

当我声明以下简单类时:

class Class1<T>
{
protected virtual T Prop1 { get; set; }
protected virtual string Prop2 { get; set; }
}

class Class2 : Class1<string>
{
protected override string Prop1 { get; set; }
protected override string Prop2 { get; set; }
}

现在我使用反射来获取 Class2 的属性,如下所示:

var hProperties = typeof(Class2).GetProperties(BindingFlags.NonPublic | BindingFlags.Instance);

那么 Prop2 将被列出一次,而 Prop1 将被列出两次!这种行为对我来说似乎很奇怪。 Prop1 和 Prop2 不应该被视为相同吗??

如何才能在 hProperties 中只拥有 Prop1 一次?我不想使用 BindingFlags.DeclaredOnly,因为我还想获得 Class1 的其他未被覆盖的 protected 属性。

最佳答案

让我们看看编译后的程序集的元数据,以确保这两个属性除了名称之外具有相同的结构:

enter image description here

我使用 ILDASM 而不是通常的反编译器工具来确保没有以更友好的方式隐藏或显示任何内容。除了名称之外,这两个属性完全相同。

两个之一Prop1返回的属性来自 Class1其中之一来自Class2 .

这似乎是一个错误。该错误似乎是基类成员未正确添加到结果中。当DeclaredOnly未指定 all inherited properties should be returned as well .

我正在使用 DotPeek 和 Reflector VS 扩展,它允许调试反编译的 BCL 代码来调试反射代码。在这个问题中看到的行为是在这个方法中触发的:

    private void PopulateProperties(RuntimeType.RuntimeTypeCache.Filter filter, RuntimeType declaringType, Dictionary<string, List<RuntimePropertyInfo>> csPropertyInfos, bool[] usedSlots, ref RuntimeType.ListBuilder<RuntimePropertyInfo> list)
{
int token = RuntimeTypeHandle.GetToken(declaringType);
if (MetadataToken.IsNullToken(token))
return;
MetadataEnumResult result;
RuntimeTypeHandle.GetMetadataImport(declaringType).EnumProperties(token, out result);
RuntimeModule module = RuntimeTypeHandle.GetModule(declaringType);
int numVirtuals = RuntimeTypeHandle.GetNumVirtuals(declaringType);
for (int index1 = 0; index1 < result.Length; ++index1)
{
int num = result[index1];
if (filter.RequiresStringComparison())
{
if (ModuleHandle.ContainsPropertyMatchingHash(module, num, filter.GetHashToMatch()))
{
Utf8String name = declaringType.GetRuntimeModule().MetadataImport.GetName(num);
if (!filter.Match(name))
continue;
}
else
continue;
}
bool isPrivate;
RuntimePropertyInfo runtimePropertyInfo = new RuntimePropertyInfo(num, declaringType, this.m_runtimeTypeCache, out isPrivate);
if (usedSlots != null)
{
if (!(declaringType != this.ReflectedType) || !isPrivate)
{
MethodInfo methodInfo = runtimePropertyInfo.GetGetMethod();
if (methodInfo == (MethodInfo) null)
methodInfo = runtimePropertyInfo.GetSetMethod();
if (methodInfo != (MethodInfo) null)
{
int slot = RuntimeMethodHandle.GetSlot((IRuntimeMethodInfo) methodInfo);
if (slot < numVirtuals)
{
if (!usedSlots[slot])
usedSlots[slot] = true;
else
continue;
}
}
if (csPropertyInfos != null)
{
string name = runtimePropertyInfo.Name;
List<RuntimePropertyInfo> list1 = csPropertyInfos.GetValueOrDefault(name);
if (list1 == null)
{
list1 = new List<RuntimePropertyInfo>(1);
csPropertyInfos[name] = list1;
}
for (int index2 = 0; index2 < list1.Count; ++index2)
{
if (runtimePropertyInfo.EqualsSig(list1[index2]))
{
list1 = (List<RuntimePropertyInfo>) null;
break;
}
}
if (list1 != null)
list1.Add(runtimePropertyInfo);
else
continue;
}
else
{
bool flag = false;
for (int index2 = 0; index2 < list.Count; ++index2)
{
if (runtimePropertyInfo.EqualsSig(list[index2]))
{
flag = true;
break;
}
}
if (flag)
continue;
}
}
else
continue;
}
list.Add(runtimePropertyInfo);
}
}

为什么公共(public)属性的行为消失了?

      if (!(declaringType != this.ReflectedType) || !isPrivate)

有一张支票。

Class1<string>.Prop2这里被过滤掉了:

              bool flag = false;
for (int index2 = 0; index2 < list.Count; ++index2)
{
if (runtimePropertyInfo.EqualsSig(list[index2]))
{
flag = true;
break;
}
}
if (flag)
continue;

因为EqualsSig返回真。如果您要求私有(private)成员,那么属性似乎会按名称和 sig 进行重复数据删除......我不知道为什么。不过,似乎是故意的。

遵循这些令人费解的代码很累人。 This is better and commented.我怀疑他们正在删除私有(private)属性,因为您可以通过从某个类继承以获取它的所有私有(private)成员来提升特权。

答案如下:

// For backward compatibility, even if the vtable slots don't match, we will still treat
// a property as duplicate if the names and signatures match.

因此他们添加了一个 hack 以实现向后兼容性。

您必须添加自己的处理才能获得所需的行为。也许,Fastreflect可以提供帮助。

关于c# - 为什么 GetProperties 两次列出 protected 属性(在通用基类中声明)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24676479/

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