2
votes

I have a class in vb.net like

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

and a class deriving from it

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

which gives me following error Public Overrides WriteOnly Property Name() As String' cannot override 'Public Overridable Property Name() As String' because they differ by 'ReadOnly' or 'WriteOnly'

but i have same construct in C#

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

public class CustomerProxy:Customer {

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

}

which works, so the first thing is , is this consistent because 2 languages are behaving in a very inconsistent way.

secondly, when i do a reflection to get a property, so for example

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

the propINfo.canRead property is always false, shouldn't this be true since base class implements the getter of the property ?

many thanks

5

5 Answers

3
votes

I'll deal with the 2nd part first. In your current vb.net code, the derived Name property replaces the original for the reflection lookup. So that reflection code only see the WriteOnly version of the property. Worse, you completely replace the backing store in your derived setter, so your getter is checking a completely different variable than the one you set.

As for the first question, when overriding properties in vb.net, you always need to override both the getter and the setter, even if you just replace it with an identical implementation:

The code should read like this:

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
votes

I'm a bit surprised by this, as it seems by the answer by Joel that this is in fact how it is supposed to work.

In my mind, however, it seems like this: "Property X can be read, even though you overrode it in a descendant class and only implemented the setter, but reflection says no, you can't read it".

This, to me, looks inconsistent. "Yes, you can read from the property using normal C# code, but no, reflection will not say that you can nor will it allow you to read from it".

Here's an example piece of code. The code reports:

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

Note that even when writing through the Value property on Base (when I have a Derived instance), it still goes through the overridden property.

and the code:

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;
            }
        }
    }
}
0
votes

The two (c# and vb) derived classes you posted are not equivalent. To try to get the same behavior (won't compile):

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

You'll get "Override accessor .... cannot change access rights". What's actually happening is you are overriding the set accessor only.

0
votes

Here is excerpt from 10.6.3 Virtual, sealed, override, and abstract accessors:

An overriding property declaration must specify the exact same accessibility modifiers, type, and name as the inherited property. If the inherited property has only a single accessor (i.e., if the inherited property is read-only or write-only), the overriding property must include only that accessor. If the inherited property includes both accessors (i.e., if the inherited property is read-write), the overriding property can include either a single accessor or both accessors.

So C# acts as expected.

0
votes

In C#, a single property declaration may generate read-only, write-only, and/or read-write properties as required to satisfy any virtual property overrides or interface implementations. If e.g. a property is needed to implement both a read-only and read-write interface, the compiler will generate a read-only property that ignores any set included in the code, and a read-write property that uses both get and set. If the property overrides a read-write property, but leaves get or set unspecified, the unspecified operation will chain to the one defined in the parent. This behavior is different from VB.NET, in which every property declaration will create exactly the kind of property indicated thereby.