vb.net C#属性覆盖机制

时间:2009-09-30 14:46:24

标签: c# .net vb.net reflection

我在vb.net中有一个类

Public Class Customer
    Private _Name As String
    Public Overridable Property Name() As String
        Get
            Return _Name
        End Get
        Set(ByVal value As String)
            _Name = value
        End Set
    End Property
End Class

和从中派生的类

Public Class ProxyCustomer
    Inherits Customer
    Private _name As String
    Public Overrides WriteOnly Property Name() As String
        Set(ByVal value As String)
            _name = value
        End Set
    End Property
End Class

这给了我以下错误 Public Overrides WriteOnly Property Name()As String'不能覆盖'Public Overridable Property Name()As String'因为它们的区别是'ReadOnly'或'WriteOnly'

但我在C#中有相同的构造

public  class Customer 
{
    public virtual string FirstName { get; set; }     
}

公共类CustomerProxy:Customer    {

   public override string FirstName
   {
       set
       {
           base.FirstName = value;
       }
   }

}

哪个有效,所以首先,这是一致的,因为2种语言的行为方式非常不一致。

其次,当我做一个反射来获得一个属性时,例如

Dim propInfo  = GetType(Customer).GetProperty("Name")

propINfo.canRead属性总是false,因为基类实现了属性的getter,所以不应该这样吗?

非常感谢

5 个答案:

答案 0 :(得分:2)

我先讨论第二部分。在当前的vb.net代码中,派生的Name属性替换了反射查找的原始属性。因此,反射代码只能看到属性的WriteOnly版本。更糟糕的是,您完全替换派生的setter中的后备存储,因此您的getter正在检查与您设置的变量完全不同的变量。

至于第一个问题,当重写vb.net中的属性时,你总是需要覆盖getter和setter,即使你只是用相同的实现替换它:

代码应如下所示:

Public Class ProxyCustomer
    Inherits Customer

    Public Overrides Property Name() As String
        Get
            Return MyBase.Name ''# Return the original parent property value
        End Get
        Set(ByVal value As String)
            MyBase.Name = value
        End Set
    End Property
End Class

答案 1 :(得分:1)

我对此感到有些惊讶,因为Joel的答案似乎确实是这应该是如何运作的。

但是,在我看来,它看起来像这样:“属性X可以读取,即使你在后代类中覆盖它并且只实现了setter,但反射说不,你不能读它”。 / p>

对我来说,这看起来不一致。 “是的,您可以使用普通的C#代码从该属性中读取,但不会,反射不会说您可以也不会允许您从中读取”。

这是一段代码示例。代码报告:

Base.Value.CanRead: True
Base.Value.CanWrite: True
Derived.Value.CanRead: False
Derived.Value.CanWrite: True
Setting via Derived.Value
Derived.Value: Test
(reflection get crashes with method Get not found, so commented it out)
Setting via Derived.Value
Base.Value: Test2

请注意,即使在Base上写入Value属性(当我有Derived实例时),它仍然会通过重写的属性。

和代码:

using System;
using System.Reflection;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            Type type = typeof(Base);
            PropertyInfo prop = type.GetProperty("Value");
            Console.Out.WriteLine("Base.Value.CanRead: " + prop.CanRead);
            Console.Out.WriteLine("Base.Value.CanWrite: " + prop.CanWrite);

            type = typeof(Derived);
            prop = type.GetProperty("Value");
            Console.Out.WriteLine("Derived.Value.CanRead: " + prop.CanRead);
            Console.Out.WriteLine("Derived.Value.CanWrite: " + prop.CanWrite);

            Derived d = new Derived();
            d.Value = "Test";
            Console.Out.WriteLine("Derived.Value: " + d.Value);
            // Console.Out.WriteLine("Reflected value: " + prop.GetValue(d, null));

            Base b = new Derived();
            b.Value = "Test2";

            Console.In.ReadLine();
        }
    }

    public class Base
    {
        public virtual String Value { get; set; }
    }

    public class Derived : Base
    {
        public override string Value
        {
            set
            {
                Console.Out.WriteLine("Setting via Derived.Value");
                base.Value = value;
            }
        }
    }
}

答案 2 :(得分:0)

您发布的两个(c#和vb)派生类不等效。要尝试获得相同的行为(不会编译):

   public override string FirstName
   {
       protected get { return base.FirstName};
       set
       {
           base.FirstName = value;
       }
   }

您将获得“覆盖访问者....无法更改访问权限”。实际发生的是你只覆盖了set accessor。

答案 3 :(得分:0)

以下是excerpt from 10.6.3 Virtual, sealed, override, and abstract accessors

  

重写属性声明必须指定与继承属性完全相同的辅助功能修饰符,类型和名称。如果继承的属性只有一个访问者(即,如果继承的属性是只读的或只写的),则覆盖属性必须只包含该访问者。如果继承的属性包含两个访问器(即,如果继承的属性是读写),则覆盖属性可以包括单个访问器或两个访问器。

所以C#按预期行事。

答案 4 :(得分:0)

在C#中,单个属性声明可以根据需要生成只读,只写和/或读写属性,以满足任何虚拟属性覆盖或接口实现。如果是需要一个属性来实现只读和读写接口,编译器将生成一个只读属性,忽略代码中包含的任何set,以及一个同时使用{{{}的读写属性1}}和get。如果属性覆盖了读写属性,但未指定setget,则未指定的操作将链接到父级中定义的操作。这种行为与VB.NET不同,其中每个属性声明都将创建由此指定的属性类型。