覆盖但不调用

发布于 2024-07-12 07:22:22 字数 272 浏览 14 评论 0原文

如何在 C# 中声明一个应该由派生类重写(或可重写)的方法(甚至可能在程序集外部),但只能从实际类中调用?

(即像 C++ 中的私有虚函数)

[编辑]
private virtual 正是我的意图:“这里有一种方法可以修改我的行为,但仍然不允许您直接调用此函数(因为调用它需要神秘的调用,只有我的基类才能执行)”

因此澄清一下:C# 中最好的表达方式是什么?

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#?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

梦里泪两行 2024-07-19 07:22:22

当您说它只能在“实际类内”调用时,您是指基类还是派生类? 这些本身都不可行。 最接近的是使用受保护的方法,这意味着可以从声明类、派生类和任何进一步派生类调用它。

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.

温柔少女心 2024-07-19 07:22:22

C# 对“私有”的保证比 C++ 更强。 在 C++ 中,您确实可以重写私有虚拟方法。 但这意味着基类中的代码可以执行派生类中的代码。 打破了私有方法是真正私有的并且只能被同一个类中的方法调用的承诺。

这里没有帮助的是 C++ 不需要重复 virtual 关键字。 导致像这样的难以逆向工程的谜团:

#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# 语言设计者说不! 尽管。

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.

雪花飘飘的天空 2024-07-19 07:22:22

私有成员对子类不可见。 我认为受保护的虚拟会按照您想要的方式执行?

更新:

这里更详细地解释了您可以在 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(); 但是当您查看动物时,如在 foreach 循环中一样,您将获得基类 DisplayAttributes 行为,而不管动物的实际类型如何。 我希望这可以帮助提供您想要复制的功能类型。

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.

素染倾城色 2024-07-19 07:22:22

这是 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);
    }
}

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);
    }
}
深白境迁sunset 2024-07-19 07:22:22

您是否考虑过使用代表来做到这一点? 您可以允许派生类通过某些受保护的属性设置委托或将其传递给构造函数。 您还可以将委托默认为内部实现,这是基类上的私有方法。

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.

空心空情空意 2024-07-19 07:22:22

为什么需要将其设为私有? 在这里,受保护应该足够了。 您要求子类作者编写他们无法调用的代码。 这能达到什么目的呢? 无论如何,他们可以使用该代码。

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.

你是年少的欢喜 2024-07-19 07:22:22

当我读到你的问题时,你可能意味着两件事。

首先,如果您想要 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 等

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.

轻许诺言 2024-07-19 07:22:22

我猜这不会按您的预期进行,但让我为您画一些伪代码:

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()) {
    }
}

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()) {
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文