Вопрос

Как вы объявляете метод в C #, который должен быть переопределен (или переопределяемым) удаляемым классом - возможно, даже вне вашей сборки, - но который должен вызываться только из самого класса?

(т.е.как частная виртуальная функция в C ++)

[править]
private virtual это именно то, что я намереваюсь:"Вот способ изменить мое поведение, но вам по-прежнему не разрешено вызывать эту функцию напрямую (потому что для ее вызова требуются тайные вызовы, которые должен выполнять только мой базовый класс)"

Итак, чтобы прояснить это:как лучше всего выразить это в C #?

Это было полезно?

Решение

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 # сказали "Нет"!хотя.

Другие советы

Когда вы говорите, что он должен вызываться только "внутри фактического класса", вы имеете в виду базовый класс или производный класс?Ни то, ни другое неосуществимо само по себе.Ближе всего использовать защищенный метод, что означает, что он может быть вызван из объявляющего класса, производного класса и любого другого производного класса.

Закрытый элемент не виден дочерним классам.Я думаю, protected virtual будет работать так, как вам хотелось бы?

Обновить:

Здесь более подробно объясняется, что вы можете делать с наследованием и переопределяющими функциями в 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, независимо от фактического типа animal.Я надеюсь, что это может помочь определить тип функциональности, которую вы хотели бы воспроизвести.

Рассматривали ли вы возможность использования делегата для этого?Вы можете разрешить производному классу устанавливать делегат через какое-либо защищенное свойство или передавать его вашему конструктору.Вы также можете по умолчанию делегировать свою внутреннюю реализацию, которая является частным методом вашего базового класса.

Вот пример того, о чем уже упоминал 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);
    }
}

Почему вам нужно, чтобы это было конфиденциально?Защищенности здесь должно быть достаточно.Вы просите автора подкласса написать код, который они не могут вызвать.Чего это дает?Они все равно могли бы использовать этот код.

Когда я читаю ваш вопрос, вы можете иметь в виду две вещи.

Во - первых , если вам нужна функция в классе 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 и т.д.

Предполагаю, что это сработает не так, как вы предполагали, но позвольте мне набросать для вас некоторый псевдокод:

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()) {
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top