如何在C#中声明一个应该被一个dereived类覆盖(或覆盖)的方法 - 甚至可能在你的程序集之外 - 但是它应该只能从实际的类中调用?
(即像C ++中的私有虚函数)
[编辑]
private
virtual
正是我想要的:“这是一种修改我的行为的方法,但你仍然不允许直接调用这个函数(因为调用它需要进行奥术调用)只有我的基类才会这样做)“
所以澄清一下:C#中最好的表达方式是什么?
答案 0 :(得分:3)
当你说它应该只能在“实际类中”可调用时,你的意思是基类还是派生类?这些都不是可行的。最接近的是使用受保护的方法,这意味着它可以从声明类,派生类和任何进一步派生的类中调用。
答案 1 :(得分:2)
子类不可见私有成员。我认为受保护的虚拟会以你想要的方式运行吗?
<强>更新强>
这里更详细地解释了你可以用C#中的继承和覆盖函数做些什么。我试图使用一个有意义的例子,但认为它理解它是一个糟糕的类设计,我不会建议实现这种方式描述的类。但是,我希望这可能会为您提供一条途径,以可接受的方式解决您的原始问题。没有办法阻止一个具体的类调用它的任何成员,但如果你的结构无论如何都是这样的,也许它不是问题。
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
}
}
}
在这个例子中,Bird,Zebra和Fish都可以调用他们的Name和Legs方法,但是在这个例子的上下文中,这样做不一定有效。另外,如Fish所示,可以为具体派生类的实例修改DisplayAttributes();但是当你在看一个Animal时,就像在foreach循环中一样,你得到了基类DisplayAttributes的行为,无论动物的实际类型如何。我希望这可能有助于提供您想要复制的功能类型。
答案 2 :(得分:1)
C#比C ++更能为“私人”提供保障。在C ++中,您确实可以覆盖私有虚方法。但这意味着基类中的代码可以在派生类中执行代码。打破私有方法真正私有的承诺,只能通过同一类中的方法调用。
这里没有帮助的是C ++不需要重复虚拟关键字。导致难以逆向设计这样的谜团:
#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();
}
我同意私人继承可能发挥作用。 C#语言设计师说不!虽然。
答案 3 :(得分:1)
您是否考虑过使用代表来做这件事?您可以允许派生类通过某些受保护属性设置委托或将其传递给构造函数。您还可以将委托默认为内部实现,这是基类上的私有方法。
答案 4 :(得分:1)
这是vboctor已经提到的一个例子:
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);
}
}
答案 5 :(得分:0)
为什么你需要它是私人的?这里保护应该足够了。您要求子类作者编写他们无法调用的代码。这取得了什么成果?无论如何,他们可以使用该代码。
答案 6 :(得分:0)
当我读到你的问题时,你可能意味着两件事。
首先,如果你想要A类中的一个函数可以在子类B中重写但是对任何外部类都不可见:
public class ClassA
{
protected virtual ReturnType FunctionName(...) { ... }
}
public class ClassB
{
protected override ReturnType FunctionName(...) { ... }
}
其次,如果要强制实现类来定义函数:
public abstract class ClassA
{
protected abstract ReturnType FunctionName(...);
}
public class ClassB
{
protected override ReturnType FunctionName(...) { ... }
}
如果您只是深入研究与C#相关的另一个概念,那就是部分类。这是两个源文件在编译时组合以创建一个类的想法,两个来自同一个程序集:
文件1:
public partial class ClassA
{
private ReturnType FunctionName(...);
}
文件2:
public partial class ClassA
{
//actual implimentation
private ReturnType FunctionName(...){ ... };
}
除了处理设计生成的文件(如Linq2Sql文件,EDM或WinForms等)时,部分未被广泛使用。
答案 7 :(得分:0)
猜猜这不会像你想象的那样有效,但让我为你画一些伪代码:
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()) {
}
}