views:

218

answers:

7

What is the 'correct' way of providing a value in an abstract class from a concrete subclass?

ie, should I do this:

abstract class A {
    private string m_Value;

    protected A(string value) {
        m_Value = value;
    }

    public string Value {
        get { return m_Value; }
    }
}

class B : A {
    B() : this("string value") {}
}

or this:

abstract class A {

    protected A() { }

    public abstract string Value { get; }
}

class B : A {
    B() {}

    public override string Value {
        get { return "string value"; }
    }
}

or something else?

And should different things be done if the Value property is only used in the abstract class?

+1  A: 

It depends; does the base-class need to know about it in the ctor? If so, the override approach may be a bad idea (virtual doesn't work very well inside the ctor). Otherwise, either is OK.

Marc Gravell
+1  A: 

I think the second idiom is better, as it is more manageable (if your base class needs multiple properties defined in a derived class, the constructor can get messy). It is also clearer where the information comes. If you see the Value property you know that it is defined in a subclass. In the first example, you have to track the definition point of the m_Value variable, which could be modified in the base class.

Mario
+1  A: 

I think it's pretty much the same, choose one way and stick to that for coherence.

Both your solutions are forcing the derived class to provide a value, which is good; a possible alternative, in case a value should not be required:

abstract class A {
    public string Value {
        get;
        protected set;
    }
}

My personal preference is your first option (constructor parameter), because I personally think that it's the clearer one, but it's really a matter of taste.

Paolo Tedesco
+1  A: 

It depends.

I will use the first way if I need to modify Valuein abstract class.

I will use the second way only if I need to inherit many classes from A and somewhere, I need to box the inherited classes to the base abstract class.

If both of the above are not true, I will use the second approach which is more manageable and clean.

If Value is only used in abstract class, I will declare it as a private field instead of a property.

Yogesh
A: 

One major advantage of the second case is that it allows a subclass to define behaviour for the Value property that may be more complex than a simple scalar value. For example, you might want to compute the Value based on other fields that the subclass defines. With the first approach, that is an impossibility, but the second approach allows for that.

Ryan Brunner
You can achieve that with the first approach by declaring the property virtual.
Jeff Sternal
+1  A: 

I usually prefer the first approach because it requires less code in child classes.

However, I admit that the semantics of the second approach are clearer in a subtle way. Overriding the property says "this property's implementation is part of my identity." Passing a constructor argument has a different connotation: "I'm setting a value in this other thing, which just happens to be my base class." It implies composition (has-a) rather than inheritance (is-a).

And should different things be done if the Value property is only used in the abstract class?

In this case, you should definitely use the first (constructor-oriented) approach so you can hide that implementation detail from subclasses.

Likewise if you need to use the value in the constructor; as Marc mentioned this is an actual technical reason to use the first approach. Though it wouldn't matter in this specific scenario, if someone later modifies the property override to use some other member variable in the derived class, you might have a subtle bug on your hands.

Jeff Sternal
A: 

I prefer the second. It lets you provide a value without adding an actual field to the class if the value is constant or can be calculated at runtime. The less state you have (fewer fields) the more maintainable you'll likely find the code to be.

munificent