c# - 为什么 CanRead 和 CanWrite 在 C# 中为具有覆盖访问器的属性返回 false?

标签 c# .net reflection system.reflection

当尝试从派生属性获取属性访问器或使用 CanRead/CanWrite 时,由于某些原因,基本自动属性未被考虑在内。

CanReadCanWrite 仅基于派生类型返回值,GetMethodSetMethod 也不会包含来自基类型的方法。

然而,当从基类型编写代码时,可以使用访问器(这样我们就可以读取仅使用派生类型中定义的 setter 的重写自动属性)。

以下是将其重现为单元测试的代码:

using System.Reflection;
using NUnit.Framework;

[TestFixture]
public class PropertiesReflectionTests
{
    public class WithAutoProperty
    {
        public virtual object Property { get; set; }
    }

    public class OverridesOnlySetter : WithAutoProperty
    {
        public override object Property
        {
            set => base.Property = value;
        }
    }

    private static readonly PropertyInfo Property = typeof(OverridesOnlySetter).GetProperty(nameof(OverridesOnlySetter.Property));

    // This one is passing
    [Test]
    public void Property_ShouldBeReadable()
    {
        var overridesOnlySetter = new OverridesOnlySetter {Property = "test"};

        Assert.AreEqual(overridesOnlySetter.Property, "test");
    }

    // This one is failing
    [Test]
    public void CanRead_ShouldBeTrue()
    {
        Assert.True(Property.CanRead);
    }

    // And this is failing too
    [Test]
    public void GetMethod_ShouldBeNotNull()
    {
        Assert.NotNull(Property.GetMethod);
    }
}

我预计最后两个测试会通过,我错过了什么?

最佳答案

I expected last two tests to pass, what am I missing?

要获得明确的答案,您必须询问最初设计 .NET 及其类型系统的人员。也就是说……

在我看来,这与反射提供有关类型编写方式的信息的目标是一致的。考虑替代方案:如果返回的 PropertyInfo 对象同时包含派生类的 setter 和基类的 getter,会怎样?从返回的结果中很难理解实际声明的位置,而且 PropertyInfo 对象本身可能会不一致。这是因为存在 PropertyInfo.DeclaringType 属性,该属性暗示成员的所有信息仅属于该声明类型。

对于既不是属性也不是事件的成员(两者都封装了一对类成员),您将获得预期的行为。当然,除非您传递 BindingFlags.DeclaredOnly,这会将返回的信息限制为声明类型。但对于那些类型的成员,DeclaringType 属性会明确告诉您成员实际声明的类型。

对于属性,DeclaringType 告诉您属性 是在哪个类中声明的。然后 SetMethodGetMethod 属性告诉您那个类声明了什么。

恕我直言,这使反射 API 更简单、更一致且更易于理解。这确实意味着你必须做更多的工作来分析虚拟属性(property)。但是,反射(reflection)总是需要“多做一点工作”。 :)

关于c# - 为什么 CanRead 和 CanWrite 在 C# 中为具有覆盖访问器的属性返回 false?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57762322/

相关文章:

c# - 具有基本类型的 ObservableCollection<T> 的自定义排序

c# - 使用wpf绘制六棱柱

c# - .Net Core - CS0012 'Object' 在未引用的程序集中定义

java - jni4net - System.Runtime.Remoting.RemotingException

java - 连接包名和类名(java 反射)

c# - 为什么反射不能访问 MulticastDelegate 变量中的 _invocationList/_invocationCount 字段?

java - 方法提取、泛型、反射

c# - 使用 ClosedXML 从 Excel 文件中读取

c# - 多线程或 GPU 计算

.net - 什么是 Microsoft.Contracts,它来自哪里?