tags:

views:

84

answers:

2

Okay, two alternatives, but before I begin, you need to know this:

public abstract class GatewayBase { ... }

public class Gateway : GatewayBase { ... }


Alternative #1

public abstract class ModelBase
{
    public GatewayBase GatewayBase { get; private set; } // property named GatewayBase

    public ModelBase(GatewayBase gateway)
    {
        GatewayBase = gateway;
    }
}

public class Model : ModelBase
{
    public Gateway Gateway { get; private set; } // property named Gateway

    public Model(Gateway gateway)
        : base(gateway)
    {
        Gateway = gateway;
    }
}


Alternative #2

public abstract class ModelBase
{
    public GatewayBase Gateway { get; private set; } // property named Gateway

    public ModelBase(GatewayBase gateway)
    {
        Gateway = gateway;
    }
}

public class Model : ModelBase
{
    public new Gateway Gateway { get; private set; } // property named Gateway plus "new" modifier

    public Model(Gateway gateway)
        : base(gateway)
    {
        Gateway = gateway;
    }
}


Discussion:

With Alternative #1, the concrete class Model can "see" two versions of Gateway. One is called GatewayBase and the other is called just Gateway, but they both contain the exact same instance. With Alternative #2, technically, there are still two versions of Gateway but one hides the other, so there is effectively only one (unless you bypass it using base.Gateway). I like that Alternative #2 lets me call the property Gateway wherever I am, because it gets used a lot in both the base and concrete classes and it's a short but clear name. Still, I have some hesitation about using the new modifier in this way. Is this really a legitimate scenario for hiding a property?

Which would you choose and why?

Or feel free to suggest other alternatives.

Thanks.

EDIT:

I should mention that GatewayBase and ModelBase are in a dependent assembly, so they don't know anything about Gateway and Model. However, Gateway and Model of course know about GatewayBase and ModelBase.

+2  A: 

Option 2 looks cleaner, but don't make a separate backing property, wrap the existing base class' property by casting it up from GatewayBase to Gateway. This way you won't have ambiguities about the Gateway used: it's always the same, just from a different perspective:

public abstract class ModelBase
{
    public ModelBase(GatewayBase gateway)
    {
        this.Gateway = gateway;
    }

    public GatewayBase Gateway { get; private set; }
}

public class Model : ModelBase
{
    public Model(Gateway gateway)
        : base(gateway)
    {
    }

    public new Gateway { get { return (Gateway) base.Gateway; } }
}

You can also use generics to keep things a little more flexible for different types of gateways (a bit like IEnumerable<T>). The problem with generics is that you can't cast one C<X> to another C<Y> (well, you can, sometimes, in 4.0). The cleanest way to solve that, is to introduce a non-generic interface, which you implement explicitly on your generic class. This way, it's hidden from view when you're talking to generic instances, but you can still mix your C<X>'s and C<Y>'s.

public interface IModel
{
    GatewayBase Gateway { get; }
}

public abstract class ModelBase<TGateway> : IModel
    where T : GatewayBase
{
    public ModelBase(TGateway gateway)
    {
        this.Gateway = gateway;
    }

    public TGateway Gateway { get; private set; }

    GatewayBase IModel.Gateway { get { return this.Gateway; } }
}

public class Model : ModelBase<Gateway>
{
    public Model(Gateway gateway)
        : base(gateway)
    {
    }
}
Ruben
Thanks, Ruben. I really like the idea of creating a property w/o making a separate backing property. Using generics is also interesting, but I think that's a little more than I need for this particular case.
DanM
A: 

I am not sure why you want the second Gateway property. Does Gateway have a different interface than GatewayBase? If so, I see the difference, but generally I think it might not be the best design. I would seriously consider whether Gateway should expose any other properties/methods than GatewayBase. If not, then you don't need the Model.Gateway property.

It is a good idea to only use inheritance when there is an "Is A" relationship between the two classes. That would imply that Gateway "Is A" GatewayBase and should generally have the same properties/methods, at least that are public.

The `Gateway` is a `GatewayBase` with added functionality. It would be like having a class `Car` with propertes engine, transmission, and wheels and a class `FastCar : Car` with engine, transmission, wheels, *and* turbocharger. A fast car *is a* car--it can do everything a car can and more. If you had a class `FastCarDriver` with a property of type `Car` (inherited from `Driver`), you'd need to do a cast every time you wanted to do something with the turbocharger. It would therefore be convenient if `FastCarDriver` had a property of type `FastCar`.
DanM