views:

369

answers:

8

How do you declare a method in C# that should be overridden (or overridable) by a dereived class - possibly even outside your assembly - but that should be callable only from within the actual class?

(i.e. like a private virtual function in C++)

[edit]
private virtual is exactly what I intend: "Here's a way to modify my behavior, but you are still not allowed to call this function directly (because calling it requires arcane invocations that only my base class shall do)"

So to clarify it: what is the best expression for that in C#?

+2  A: 

A private member is not visible to child classes. I think protected virtual will perform the way you'd like?

UPDATE:

Here in greater detail is an explaination of what you can do with inheritance and overriding functions within C#. I tried to use a somewhat meaningful example, but consider it understood that its a poor class design and I wouldn't ever recommend implementing the classes described in this way. However, I hope perhaps this will give you an avenue to approach solving your original problem in a manner that might be acceptable. There is no way to prevent a concrete class from calling any of its members, but if your structure is like this in anyway, perhaps its not issue.

public abstract class Animal
{
    public void DisplayAttributes()
    {
        Console.WriteLine(Header());
        Console.WriteLine("Name: " + Name());
        Console.WriteLine("Legs: " + Legs());
        Console.WriteLine();
    }

    protected virtual int Legs()
    {
        return 4;
    }

    private string Header()
    {
        return "Displaying Animal Attributes";
    }

    protected abstract string Name();
}

public class Bird : Animal
{
    protected override string Name()
    {
        return "Bird";
    }

    protected override int Legs()
    {
        return 2;
    }
}

public class Zebra : Animal
{
    protected override string Name()
    {
        return "Zebra";
    }
}

public class Fish : Animal
{
    protected override string Name()
    {
        return "Fish";
    }

    protected override int Legs()
    {
        return 0;
    }

    private string Header()
    {
        return "Displaying Fish Attributes";
    }

    protected virtual int Gils()
    {
        return 2;
    }

    public new void DisplayAttributes()
    {
        Console.WriteLine(Header());
        Console.WriteLine("Name: " + Name());
        Console.WriteLine("Gils: " + Gils());
        Console.WriteLine();
    }
}

class Program
{
    static void Main(string[] args)
    {
        Bird bird = new Bird();
        bird.DisplayAttributes();
        //Displaying Animal Attributes
        //Name: Bird
        //Legs: 2

        Zebra zebra = new Zebra();
        zebra.DisplayAttributes();
        //Displaying Animal Attributes
        //Name: Zebra
        //Legs: 4


        Fish fish = new Fish();
        fish.DisplayAttributes();
        //Displaying Fish Attributes
        //Name: Fish
        //Gils: 2

        List<Animal> animalCollection = new List<Animal>();
        animalCollection.Add(bird);
        animalCollection.Add(zebra);
        animalCollection.Add(fish);

        foreach (Animal animal in animalCollection)
        {
            animal.DisplayAttributes();
            //Displaying Animal Attributes
            //Name: Bird
            //Legs: 2

            //Displaying Animal Attributes
            //Name: Zebra
            //Legs: 4

            //Displaying Animal Attributes
            //Name: Fish
            //Legs: 0
            //*Note the difference here
            //Inheritted member cannot override the
            //base class functionality of a non-virtual member
        }
    }
}

In this example, Bird, Zebra, and Fish could all call their Name and Legs methods, but within the context if this example, there wouldn't necessarily be utility in doing so. Additionally, as shown by Fish, the DisplayAttributes() can be modified for an instance of a concrete derived class; but when you're looking at an Animal, as in the foreach loop, you get the base classes DisplayAttributes behavior, regardless of the actual type of animal. I hope this may help povide the type of functionality you would like to replicate.

Timothy Carter
protected virtual was what I meant, without thinking about it
Tom Ritter
I C++ a private virtual function cannot be accessed, but still overridden (VS 2005 managed C++ already doesn't allow it, though)
peterchen
A: 

Why do you need it to be private? Protected should be sufficient, here. You're asking the subclass author to write code that they can't call. What does this accomplish? They could use that code anyway.

Yuliy
+3  A: 

When you say it should only be callable "within the actual class" do you mean the base class or the derived class? Neither of these is feasible on its own. The closest is to use a protected method, which means it can be called from the declaring class, the derived class, and any further-derived class.

Jon Skeet
A: 

As I read your question, you could mean two things.

First ,if if you want a function in Class A that can be overriden in Child Class B but is not visible to any outside class:

public class ClassA
{
  protected virtual ReturnType FunctionName(...) { ... }
}

public class ClassB
{
  protected override ReturnType FunctionName(...) { ... }
}

Second, if you want to force an implementing class to define the function:

public abstract class ClassA
{
  protected abstract ReturnType FunctionName(...);
}

public class ClassB
{
  protected override ReturnType FunctionName(...) { ... }
}

Another concept you might look at if you are just digging into C# that is kinda related is partial classes. This is the idea of two source files being combined at compile time to create one class, both from the same assembly:

File 1:

public partial class ClassA
{
    private ReturnType FunctionName(...);
}

File 2:

public partial class ClassA
{
  //actual implimentation
  private ReturnType FunctionName(...){ ... }; 
}

Partials are not widely used except when dealing with designed-generated files, like the Linq2Sql files, or EDM, or WinForms, etc.

Jason Jackson
In your second code-block, you declared A.FunctionName as abstract, but then still gave it a function body "{ ... }". This will lead to a compiler error, won't it?
abelenky
Yup. That is what I get for typing it into SO instead of the IDE, then not checking my code very closely. Fiexed.
Jason Jackson
A: 

Guess this will not work out as you intended, but let me sketch some pseudo-code for you:

public interface BaseClassFunction {
    void PleaseCallMe();
}

public class BaseClass {
    private BaseClassFunction fn;
    public BaseClass(BaseClassFunction fn) {
        this.fn = fn;
    }
    private CallMe() {
        fn.PleaseCallMe();
    }
    public PublicCallMe() {
        CallMe();
    }
}

private class DerivedClassFunction : BaseClassFunction {
    void PleaseCallMe() { ... do something important ... }
}

public class DerivedClassFunction {
    public DerivedClassFunction() : BaseClass(new DerivedClassFunction()) {
    }
}
devio
+1  A: 

C# makes a stronger guarantee for "private" than C++ does. In C++, you can indeed override a private virtual method. But that means that code in a base class can execute code in a derived class. Breaking the promise that the private method is truly private and can only be called by methods in the same class.

Something that doesn't help here is that C++ doesn't require repeating the virtual keyword. Leading up to hard to reverse-engineer mysteries like this one:

#include "stdafx.h"
#include <iostream>

class Base {
private:
    virtual void Method() = 0;
public:
    void Test() {
        Method();
    }
};
class Derived : public Base {
private:
    void Method() { std::cout << "Who the heck called me?"; }
};

int _tmain(int argc, _TCHAR* argv[])
{
    Base* p = new Derived;
    p->Test();
}

I agree there's a possible role for private inheritance. The C# language designers said No! though.

Hans Passant
That reasoning ("stonger guarantee") makes sense. - So you agree with above posts to make it protected?
peterchen
Yes, protected virtual is your only alternative.
Hans Passant
Make that protected abstract
Hans Passant
well, abstract vs. virtual depends on the base class having/not having a default implementation, but yeah :).
peterchen
+1  A: 

Did you consider the use of a delegate to do that? You can allow the derived class to set the delegate via some protected property or passing it to your constructor. You can also default the delegate to your internal implementation which is a private method on your base class.

vboctor
+1  A: 

Here's an example of what vboctor has already mentioned:

public class Base
{
    private Func<Base, int> func;
    protected void SetFunc(Func<Base, int> func)
    {
        this.func = func;
    }

    private void CallFunc()
    {
        if (func != null)
        {
            var i = func(this);
        }
    }
}

public class Sub : Base
{
    private void DoFuncyStuff()
    {
         this.SetFunc(b => 42);
    }
}
Jonathan Parker
Thanks for the reply. In my application, I'll stick with the "don't call directly" commment, but it's a good solution when that level of isolation needs to be enforced.
peterchen