views:

257

answers:

5

Here is an example. I have two classes, one inherited, and both have a function with the same name, but different arguments:

public class MyClass
{
    //public class members

    public MyClass()
    {
        //constructor code
    }

    public void Copy(MyClass classToCopy)
    {
        //copy code
    } 
}

public class InheritedClass : MyClass
{
    //public class members

    public InheritedClass():base()
    {
        //constructor code
    }

    public void Copy(InheritedClass inheritedClassToCopy)
    {
        //copy code
    } 
}

My question is how do I make the base class' copy method (MyClass.Copy) non-inheritable or non-visible in InheritedClass? I don't want to be able to do this:

MyClass a;
InheritedClass b;
b.Copy(a);

Does this make sense, or should I keep this functionality in there? Can what I'm asking even be done?

+18  A: 

Does this make sense, or should I keep this functionality in there? Can what I'm asking even be done?

Trying to hide a public method like this when used by a base class is problematic. You're purposely trying to violate the Liskov substitution principle.

alt text

Reed Copsey
Ok, I had never seen that before. This makes sense.
Mike Webb
Hope you don't mind that I added the motivator poster ;)
jgauffin
@jgauffin: Lol...
Reed Copsey
@jgauffin - I like that poster. lol
Mike Webb
+1 Nice illustration that says it all! =)
Will Marcouiller
I am stealing that image! **EDIT** I mean, of course, I am downloading it and storing it for reuse in a manner wholly in compliance with the relevant license agreement. :P
Andrew Barber
+5  A: 

You can't do what you are wanting to do here; C# does not allow negative variance in inherited members. (almost no languages truly do, actually)

It may be that you don't want an inherited class here at all, though; what you may really want is an interface. Or... your two classes here may not have the correct relationship; perhaps they should both instead be common siblings of a third class, which is their parent.

Andrew Barber
+4  A: 

You can use explicit interface implementation to hide this method from the inheritor. But you will need to add an interface of course and you will need to cast your type to the interface to call your method:

public interface MyInterface
{
    void Copy(MyClass classToCopy)
}

public class MyClass : MyInterface
{
    void MyInterface.Copy(MyClass classToCopy)
    {
        //copy code
    } 
}
Andrew Bezzub
+1, might address the OP's ultimate requirement well with a little refactoring.
Kirk Woll
+2  A: 

This is not possible. An inherited class inherits all public and protected members, methods and properties. Using the sealed modifier with make it non-overridable, but still accessible to your inherited class.

Bernard
+1  A: 

What everyone else said, but if I am inferring your goal correctly, it is to make sure that InheritedClass users never use the MyClass method. In that case, exclude it from MyClass and make two classes that inherit it.

Make MyBaseClass abstract if it should not be instantiated (most likely).

(Edited -- you probably would want to include copy code for anything that's part of the base class in the base class)

public abstract class MyBaseClass
{
    public MyClass()
    {
        //constructor code
    }
    protected void Copy(MyBaseClass classToCopy)
    {
        //copy code
    }
    // other methods that all inherited classes can use
}

public class MyClass: MyBaseClass
{
    public MyClass():base()
    {
        //constructor code
    }
    public void Copy(MyClass myClassToCopy)
    {
        base.Copy(myClassToCopy);
        //specific copy code for this extensions in this class
    } 
}

public class InheritedClass : MyBaseClass
{
    public InheritedClass():base()
    {
        //constructor code
    }
    public void Copy(InheritedClass inheritedClassToCopy)
    {
        base.Copy(myClassToCopy);
        //specific copy code for this extensions in this class
    } 
}
jamietre
@jamietre: Is there any way to have two or more public classes which inherit a common ancestor, without allowing outside code to derive classes from that common ancestor? For example, if the base class is supposed to be for immutable objects, and the only classes which derive from it are semantically immutable, all is good. But if the base class can be derived via outside code, outside code could create a mutable "immutable" object.
supercat
@supercat: You can use an `internal` constructor.
Jordão
I'm not exactly sure I understand the situation you are trying to avoid. If the base class is marked abstract then you can create classes which inherit it but you cannot actually create an instance of the base class. This means you can create code that accepts polymporhps of BaseClass even though no such entity as BaseClass can be created. If you are trying to hide the abstract class from other code, you can't do that, since you would then be unable to use the base class as a polymorphic type for procedures which should be able to use inherited classes. Which is the point of inheritance.
jamietre
@Jordão I stand corrected, you can do that! In practice, wouldn't that just make the two inherited classes usable only as completely unrelated objects? Seems to defeat the purpose of inheritance.
jamietre
@jamietre: The idea would be that the class would be inheritable within a limited scope (since if it weren't inheritable no derived types could be created) but not //inheritable// outside that scope. If it can't be done, it can't be done--it's not worth going to extreme lengths to provide protection that can be bypassed via Reflection anyway--but if there's a clean way to do it, it would seem nice.
supercat
@supercat, got it, it sounds like you can do this with `internal` but you would have to put the code in a separate assembly (internal hides it from external assemblies). If your goal is to prevent this behavior from users other than yourself then this seems a reasonable solution. If you're trying to protect yourself from inheriting your own class in an application, ...well.. fair enough. I can't swear I've never abused my own code accidentally before. I don't know of a way other than a separate assembly, though.
jamietre
Sorry for the many comments (this is actually pretty interesting to me). It occurs to me that if you want to be able to refer to the base class (as a type that accepts any inherited classes) but prevent the creation of new inherited classes within that same scope, you're out of luck.
jamietre
You can also have a private constructor in your base class, and create your derived classes as nested classes of the base class. They'll will still be able to call that constructor.
Jordão