tags:

views:

557

answers:

9

I have a class called 'Ship' and a class called 'Lifeboat'

Lifeboat inherits from Ship.

Ship contains a method called Validate() which is called before save and it has an abstract method called FurtherValidate() which it calls from Validate. The reason this is in place is so when you call validate on the base it also validates the class that is inheriting. So we have

public class Ship

public bool Validate()
{
//validate properties only found on a ship

FurtherValidate();
}

public abstract bool FurtherValidate();

So Lifeboat has

public override bool FurtherValidate()
{
//validate properties only found on a lifeboat
}

This means anyone implementing Ship also needs to provide there own validation for there class and it's guaranteed to be called on the save as the base ship.Validate() is called which in turns calls the inherited validate.

How can we re work this so we still force inherited classes to implement FurtherValidate() but FurtherValidate() can never be called by the programmer. Currently you can called Lifeboat.FurtherValidate and I want to somehow prevent this.

Thanks

+1  A: 

Making it protected instead of public will at least prevent outside objects from calling it.

Stephan Leclercq
+7  A: 
protected abstract bool FurtherValidate();

only Ship and Lifeboat can see it now.

EDIT: Lifeboat must be able to see it. How should it be able to override FurtherValidate when it can't even see it. I would rename it to ValidateCore, the 'Core' part (to me) implies that it should not be called without a very good reason.

I don't think it's easy to make it abstract but not visible. You need to have some faith in your lifeboat ;)

alvin
But it still can be called from the Lifeboat
Dev er dev
Right, isn't that the point though? He wants subclasses to have to implement a method without outsiders accessing the method because its only meaningful when invoked by the super class.
cfeduke
No, he wants the subclasses to have to implement it but ensure that they don't call it arbitrarily except through a call to Ship.Validate().
Scott Dorman
It's actually hard sometimes explaining what I want to achieve :).
Robert
A: 

You could mark the method as protected so only inheriting classes can access it. This does not prevent inheritors from exposing the method through another public method but that's usually not a major concern.

cfeduke
+3  A: 

The most simple answer would be to make the method protected. This allows the inheritors to call it but does not make it publicly available. However there is nothing to stop the inheriting classes changing the method to public.

I would be more inclined to remove the FurtherValidate method entirely and have any inheriting classes override Validate, calling base.Validate() if they wish. This allows any class that inherits from ship to have a greater degree of control over the validate method.

Jack Ryan
The problem with that scenario is there is then no way to ensure that the overriden Validate methods do actually call base.Validate(). In the scenario presented, the OP always wants the base Validate() method to be called.
Scott Dorman
Having the abstract method doesnt ensure it either because it is still possible to override the base Validate method. I think it is the responsibility of the inheriting class to ensure that any methods that it overrides still fulfil their purpose.
Jack Ryan
It's possible to hide the base Validate method with a new Validate method. If you don't use the new keyword you will get a compiler warning and if you use the new keyword it's explicit that you're hiding the method...
Scott Dorman
Naming convention: OnValidate() (like an event handler OnClick etc). It is advised to call the base.OnValidate() when overriding it.
alvin
...The abstract FurtherValidate only ensures that the derived class will implement it. The way Validate is implemented ensures that it will always be called.
Scott Dorman
@alvin: That naming convention is really only applied to events and event handlers. Just because you're overriding a method doesn't mean it should be named OnXxxx.
Scott Dorman
What i meant was: when you override a method OnXxxx you should call base.OnXxxx in the overriding method. Just like with events.
alvin
A: 

Probably you could try the private modifier

Making it private will hide it from the derived classes completely and it won't be available to override.
Scott Dorman
+7  A: 

Short answer is, you can't hide the derived method from the class that's deriving it. However, you can refactor your code to accomplish what you're trying to achieve:

public class Ship
{    
    public virtual bool Validate()    
    {        
        //validate properties only found on a ship
        return true;
    }
}
public class Lifeboat : Ship
{   
    public override bool Validate()   
    {       
        base.Validate();       
        // lifeboat specific code
        return true;
    }
}
Robert S.
The problem with that scenario is there is then no way to ensure that the overriden Validate methods do actually call base.Validate(). In the scenario presented, the OP always wants the base Validate() method to be called.
Scott Dorman
If the developer calls Lifeboat.Validate(), then base.Validate() gets called.
Robert S.
Right...the problem is that there is no way to guarantee that the developer who wrote Lifeboat.Validate included the call to base.Validate().
Scott Dorman
Oh I see what you mean. I'm operating under the assumption that the code is written, as in my answer. You're referring to code that will be written, which means that the developer may choose to exclude the base call. The code here works, but future code may not.
Robert S.
Brilliant answer though and makes good sense but your right it relies on the developer to call base.validate and I was hoping for a way to eliminiate that concern :). But good answer nicely explained and I should of considered it myself.
Robert
This is your best solution. You can never ensure future coders call anything since they could just change it so it is callable anyways. This is the cleanest way to implement what the intention of the code is disregarding what future coders may do.
Alex
+2  A: 

protected is the correct approach here. But in another situation, you may wish to use editorbrowsableattribute which will hide the method from intellisense. You can still call it, but it slows down devs from calling something that could blow up the program, and will usually force them to read your giant comment-warnings.

Tom Ritter
That's an excellent suggestion.
Robert S.
Good idea! BTW I'm amazed how many answers this question gets.
alvin
The EditorBrowsable attribute is an IDE trick that only hides it from IntelliSense and only if VS isn't configured to show advanced members (the default is to hide them).
Scott Dorman
This is going to be an excellent way to further my cause, although its not concrete it appears to be the closest way to achieve my goals as quite frankly the developers I know totally rely on the IDE as pretty much do I now.
Robert
This answer is silly. Why not make FurtherValidate() protected?
EricSchaefer
+4  A: 

The exact scenario you describe isn't possible. You can restrict access to the FurtherValidate method to only derived classes by using the protected access modifier. You could also restrict it to only classes in the same assembly by using the internal modifier, but this would still allow the programmer writing the derived class to call FurtherValidate any time they wish. Using both protected and internal combines the two and really means that is restricted to derived classes or classes defined in the same assembly.

Using the [EditorBrowsable] attribute is an IDE trick that will hide the method from IntelliSense (unless the other programmer has turned on the right options in VS). That will effectively prevent most people from calling it (if they can't see it, it doesn't exist).

You could possibly achieve this using reflection to interrogate who your caller is, but I think the performance costs of doing this would be too high compared to the benefit.

Scott Dorman
In C#, adding internal to a class marked protected widens the visibility, rather than narrowing it. In the IL, this gets compiled as ProtectedOrInternal, which means that ANY inheriting class can see it, and ANY class in the assembly can see it. IL also has ProtectedAndInternal, but not C#.
Neil Whitaker
I'm going for the IDE attribute as a good way forward. Thanks very much
Robert
Yes, if you add both protected and internal it widens the visibility as it does really mean "protected or internal".
Scott Dorman
A: 

I see a code smell here, since Validate isn't part of the functional responsibility of a ship. In other words, I think maybe you're trying to solve a problem using inheritance when maybe that's not the best solution. Try refactoring your validation logic so that you inject your validation in to the class. This will make better sense in terms of a domain object Ship, since ships don't validate themselves, they're validated externally. If you want to enforce that there must be a validator, then you can throw an exception if the property is null.

protected IValidator FurtherValidation { private get; set; }

public bool Validate()
{
//validate properties only found on a ship

    if (FurtherValidation == null)
        throw new ValidationIsRequiredException();
    if (!FurtherValidation.IsValid(this))
        // logic for invalid state
}
Michael Meadows
Thanks :), but it's not really a ship the scenario is made up just for the question. In this case the object is part of the model and the model is responsible for validating itself in this instance before it's saved.
Robert
I would still suggest you lean toward composition over inheritance. The fact that you can't solve your problem cleanly with inheritance is indicative of the fact that it's probably the wrong solution.
Michael Meadows