views:

2185

answers:

10

Why do you think (or, why is it good that) Microsoft chose not to allow:

    public abstract class BaseClass
    {
        public abstract int Bar { get;}
    }

    public class ConcreteClass : BaseClass
    {
        public override int Bar
        {
            get { return 0; }
            set {}
        }
    }
A: 

Because at the IL level, a read/write property translates into two (getter and setter) methods.

When overriding, you have to keep supporting the underlying interface. If you could add a setter, you would effectively be adding a new method, which would remain invisible to the outside world, as far as your classes' interface was concerned.

True, adding a new method would not be breaking compatibility per se, but since it would remain hidden, decision to disallow this makes perfect sense.

Ishmaeel
I don't care much about "the outside world" here. I want to add functionality to a class, which is always visible only to code that knows the specific class and not the base.
ripper234
+1  A: 

Because that would break the concept of encapsulation and implementation hiding. Consider the case when you create a class, ship it, and then the consumer of your class makes himself able to set a property for which you originally provide a getter only. It would effectively disrupt any invariants of your class which you can depend on in your implementation.

petr k.
+11  A: 

Because the writer of Baseclass has explicitly declared that Bar has to be a read-only property. It doesn't make sense for derivations to break this contract and make it read-write.

I'm with Microsoft on this one.
Let's say I'm a new programmer who has been told to code against the Baseclass derivation. i write something that assumes that Bar cannot be written to (since the Baseclass explicitly states that it is a get only property). Now with your derivation, my code may break. e.g.

public class BarProvider
{ BaseClass _source;
  Bar _currentBar;

  public void setSource(BaseClass b)
  {
    _source = b;
    _currentBar = b.Bar;
  }

  public Bar getBar()
  { return _currentBar;  }
}

Since Bar cannot be set as per the BaseClass interface, BarProvider assumes that caching is a safe thing to do - Since Bar cannot be modified. But if set was possible in a derivation, this class could be serving stale values if someone modified the source object's Bar property externally. The point being 'Be Open, avoid doing sneaky things and surprising people*'

Update: Ilya Ryzhenkov asks 'Why don't interfaces play by the same rules then?' Hmm.. this gets muddier as I think about it.
An interface is a contract that says 'expect an implementation to have a read property named Bar.' Personally I'm much less likely to make that assumption of read-only if I saw an Interface. When i see a get-only property on an interface, I read it as 'Any implementation would expose this attribute Bar'... on a base-class it clicks as 'Bar is a read-only property'. Of course technically you're not breaking the contract.. you're doing more. So you're right in a sense.. I'd close by saying 'make it as hard as possible for misunderstandings to crop up'.

Gishu
I am still not convinced. Even if there is no explicit setter, this doesn't guarantee that the property will always return the same object - it can still be changed by some other method.
ripper234
Updated with an example.. HTH
Gishu
Shouldn't the same be true for interfaces, then? You can have readonly property on interface and read/write on implementing type.
Ilya Ryzhenkov
Nice question... feeble attempt at answering it above :)
Gishu
@Gishu don't beat yourself up, you're pretty much there.
Shaun Austin
@Ilya. No the same doesn't neccesarilly follow for interfaces as they are effectively "view" into the implementing type. So an interface will always expose either the same or fewer members than are part of the implementing type.
Shaun Austin
I disagree: the base class only declared the property as having no setter; that is not the same as the property being read-only. "Read-only" is only a meaning *you* assign to it. There are no relevant guarantees built into C# at all. You could have a get-only property that changes every time, or a get/set property where the setter throws an `InvalidOperationException("This instance is read-only")`.
romkyns
+3  A: 

You could perhaps go around the problem by creating a new property:

public new int Bar 
{            
    get { return 0; }
    set {}        
}

int IBase.Bar { 
  get { return Bar; }
}
Hallgrim
A: 

Because a class that has a read-only property (no setter) probably has a good reason for it. There might not be any underlying datastore, for example. Allowing you to create a setter breaks the contract set forth by the class. It's just bad OOP.

Joel Coehoorn
+1  A: 

I can understand all your points, but effectively, C# 3.0's automatic properties get useless in that case.

You can't do anything like that:

public class ConcreteClass : BaseClass
{
    public override int Bar
    {
        get;
        private set;
    }
}

IMO, C# should not restrict such scenarios. It's the responsibility of the developer to use it accordingly.

Thomas Danecker
I don't understand your point. Do you concur that C# should allow adding a setter, or are you with most of the other people that answered this question?
ripper234
As I said, IMO, C# should allow adding a setter. It's the responsibility of the developer to use it accordingly.
Thomas Danecker
+1  A: 

I think the main reason is simply that the syntax is too explicit for this to work any other way. This code:

public override int MyProperty { get { ... } set { ... } }

is quite explicit that both the get and the set are overrides. There is no set in the base class, so the compiler complains. Just like you can't override a method that's not defined in the base class, you can't override a setter either.

You might say that the compiler should guess your intention and only apply the override to the method that can be overridden (i.e. the getter in this case), but this goes against one of the C# design principles - that the compiler must not guess your intentions, because it may guess wrong without you knowing.

I think the following syntax might do nicely, but as Eric Lippert keeps saying, implementing even a minor feature like this is still a major amount of effort...

public int MyProperty
{
    override get { ... }
    set { ... }
}

or, for autoimplemented properties,

public int MyProperty { override get; set; }
romkyns
A: 

Check out this link for more Info on this!

http://msdn.microsoft.com/en-us/library/aa288470(VS.71).aspx

+2  A: 

This is not impossible. You simply have to use the "new" keyword in your property. For example,

namespace {
    public class Base {
        private int _baseProperty = 0;

        public virtual int BaseProperty {
            get {
                return _baseProperty;
            }
        }

    }

    public class Test : Base {
        private int _testBaseProperty = 5;

        public new int BaseProperty {
            get {
                return _testBaseProperty;
            }
            set {
                _testBaseProperty = value;
            }
        }
    }
}

It appears as if this approach satisfies both sides of this discussion. Using "new" breaks the contract between the base class implementation and the subclass implementation. This is necessary when a Class can have multiple contracts (either via interface or base class).

Hope this helps, Matt Bolt

mbolt35
+1  A: 

I stumbled across the very same problem today and I think a have a very valid reason for wanting this.

First I'd like to argue that having a get-only property doesn't necessarily translate into read-only. I interpret it as "From this interface/abtract you can get this value", that doesn't mean that some implementation of that interface/abstract class wont need the user/program to set this value explicitly. Abstract classes serve the purpose of implementing part of the needed functionality. I see absolutely no reason why an inherited class couldn't add a setter without violating any contracts.

The following is a simplified example of what I needed today. I ended up having to add a setter in my abstract class just to get around this. The reason for adding the setter and not adding, say, a SetProp method is that one particular implementation of the interface used DataContract/DataMember for serialization of Prop, which would have been made needlessly complicated if I had to add another property just for the purpose of serialization.

    interface ITest
{
    // Other stuff
    string Prop { get; }
}

// Implements other stuff
abstract class ATest : ITest
{
    abstract public string Prop { get; }
}

// This implementation of ITest needs the user to set the value of Prop
class BTest : ATest
{
    string foo = "BTest";
    public override string Prop
    {
        get { return foo; }
        set { foo = value; } // Not allowed. 'BTest.Prop.set': cannot override because 'ATest.Prop' does not have an overridable set accessor
    }
}

// This implementation of ITest generates the value for Prop itself
class CTest : ATest
{
    string foo = "CTest";
    public override string Prop
    {
        get { return foo; }
        // set; // Not needed
    }
}

I know this is just a "my 2 cents" post, but I feel with the original poster and trying to rationalize that this is a good thing seems odd to me, especially considering that the same limitations doesn't apply when inheriting directly from an interface.

Also the mention about using new instead of override does not apply here, it simply doesn't work and even if it did it wouldn't give you the result wanted, namely a virtual getter as described by the interface.

JJJ