Reputation: 42384
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
.
Upvotes: 0
Views: 166
Reputation: 11
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.
Upvotes: 0
Reputation: 15555
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)
{
}
}
Upvotes: 2