Почему C# не предоставляет ключевое слово friend в стиле C++?

C++ friend keyword позволяет class A назначать class B своим другом. Это 9X_pattern позволяет Class B получать доступ к элементам private / protected в 9X_cxx class A.

Я никогда не читал ничего о том, почему 9X_csharp это было исключено из C# (и VB.NET). В большинстве 9X_gof ответов на этот earlier StackOverflow question, похоже, говорится, что 9X_cpp это полезная часть C++ и есть веские причины 9X_c#.net для ее использования. По моему опыту, я 9X_oo бы согласился.

Другой question, кажется, действительно 9X_cpp спрашивает, как сделать что-то похожее на 9X_csharp friend в приложении C#. Хотя ответы обычно касаются 9X_friend вложенных классов, это не кажется таким 9X_oop элегантным, как использование ключевого 9X_pattern слова friend.

Исходный Design Patterns book регулярно использует его 9X_friend в своих примерах.

Итак, вкратце, почему friend отсутствует 9X_c-sharp в C# и каков «наилучший» способ (или способы) его 9X_c-sharp моделирования на C#?

(Кстати, ключевое слово 9X_gof internal - это не одно и то же, оно позволяет всем классам 9X_object-oriented-design внутри всей сборки получать доступ к членам 9X_design-pattern internal, тогда как friend позволяет предоставить определенному 9X_oo классу полный доступ к ровно одному другому классу)

220
6

  • Я чувствую себя защищенным изнутри - хо ...
19
Общее количество ответов: 19

Ответ #1

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

На заметку. Использование друга - это не 9X_cpp нарушение инкапсуляции, а, наоборот, обеспечение 9X_oop ее соблюдения. Подобно аксессорам + мутаторам, перегрузке 9X_csharp операторов, общедоступному наследованию, понижающему 9X_c#.net преобразованию, и т. Д., он часто используется 9X_patterns неправильно, но это не означает, что ключевое 9X_object-oriented-design слово не имеет или, что еще хуже, плохой 9X_friend цели.

См. message Konrad Rudolph в другом потоке или, если вы 9X_cpp предпочитаете, the relevant entry в FAQ по C++.

111
4

  • Думаю, дело в семантическом мнении; и, возможно, связаны с конкретной рассматриваемой ситуацией. Сделав класс «другом», вы получите доступ ко ВСЕМ вашим закрыты ...

Ответ #2

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

Наличие друзей-программистов более или менее 9X_c-sharp считается "грязным", и им легко злоупотреблять. Это 9X_cpp нарушает отношения между классами и подрывает 9X_oops некоторые фундаментальные атрибуты объектно-ориентированного 9X_cpp языка.

При этом это хорошая функция, и я 9X_patterns сам много раз использовал ее на C++; и хотел 9X_patterns бы использовать его и в C#. Но я уверен, что 9X_oo из-за "чистой" OOness C# (по сравнению с 9X_cpp псевдо OOness C++) MS решила, что, поскольку 9X_design-patterns у Java нет ключевого слова друга, C# тоже 9X_object-oriented-design не должен (шутка;))

Если серьезно: Internal 9X_oop не так хорошо, как друг, но он выполняет 9X_oop свою работу. Помните, что вы редко будете 9X_object-oriented-design распространять свой код сторонним разработчикам 9X_c-sharp не через DLL; так что пока вы и ваша команда 9X_oops знаете о внутренних классах и их использовании, все 9X_oops будет в порядке.

ИЗМЕНИТЬ. Позвольте мне пояснить, как 9X_patterns ключевое слово "друг" подрывает ООП.

Частные 9X_cpp и защищенные переменные и методы, пожалуй, одна 9X_c#.net из самых важных частей ООП. Идея о том, что 9X_pattern объекты могут содержать данные или логику, которые 9X_cxx могут использовать только они, позволяет 9X_pattern вам писать свою реализацию функциональности 9X_c-sharp независимо от вашей среды - и что ваша среда 9X_oop не может изменять информацию о состоянии, для 9X_design-pattern обработки которой она не подходит. Используя 9X_patterns friend, вы объединяете реализации двух классов 9X_c++ вместе - что намного хуже, чем если бы вы 9X_oo просто объединили их интерфейс.

70
12

  • Не уверен, насколько серьезно вы шутите по поводу "псевдо-объектно-ориентированного" C++ и "чистого объектно-ориентированного подхода" в C#, но точно известно, что объектно-ориентированность никоим образом не подразумевает ...

Ответ #3

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

Для информации, еще одна связанная, но не 9X_pattern совсем такая же вещь в .NET - это [InternalsVisibleTo], который 9X_object-oriented позволяет сборке назначать другую сборку 9X_patterns (например, сборку модульного теста), которая 9X_pattern (по сути) имеет "внутренний" доступ к типам 9X_c++ / элементам в исходной сборке.

51
1

  • хороший совет, так как, вероятно, часто люди, ищущие друга, хотят найти способ пройти модульное тестирование с возможностью получить больш ...

Ответ #4

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

Фактически, C# дает возможность получить 9X_design-pattern такое же поведение в чистом виде ООП без 9X_friend специальных слов - это частные интерфейсы.

Поскольку 9X_visual-c# вопрос What is the C# equivalent of friend? был помечен как дубликат этой статьи, и 9X_c# никто из них не предлагает действительно 9X_visual-c# хорошей реализации - я покажу здесь ответы 9X_design-patterns на оба вопроса.

Основная идея была взята 9X_gof отсюда: What is a private interface?

Допустим, нам нужен какой-то класс, который 9X_c#.net мог бы управлять экземплярами других классов 9X_gof и вызывать для них какие-то специальные 9X_oops методы. Мы не хотим давать возможность вызывать 9X_friend эти методы другим классам. Это в точности 9X_cpp то же самое, что ключевое слово friend c 9X_gof ++ делает в мире c ++.

Я думаю, что хорошим 9X_c# примером на практике может быть шаблон Full 9X_patterns State Machine, когда какой-либо контроллер 9X_c-sharp обновляет объект текущего состояния и при 9X_c#.net необходимости переключается на другой объект 9X_design-pattern состояния.

Вы могли:

  • Самый простой и худший способ сделать метод Update() общедоступным - надеюсь все понимают, почему это плохо.
  • Следующий способ - пометить его как внутренний. Достаточно хорошо, если вы положите классы в другую сборку, но даже тогда каждый класс в этой сборке может вызывать каждый внутренний метод.
  • Используйте частный / защищенный интерфейс - и я пошел по этому пути.

Controller.cs

public class Controller
{
    private interface IState
    {
        void Update();
    }

    public class StateBase : IState
    {
        void IState.Update() {  }
    }

    public Controller()
    {
        //it's only way call Update is to cast obj to IState
        IState obj = new StateBase();
        obj.Update();
    }
}

Program.cs

class Program
{
    static void Main(string[] args)
    {
        //it's impossible to write Controller.IState p = new Controller.StateBase();
        //Controller.IState is hidden
        var p = new Controller.StateBase();
        //p.Update(); //is not accessible
    }
}

А как насчет наследования?

Нам 9X_friend нужно использовать технику, описанную в 9X_oo Since explicit interface member implementations cannot be declared virtual, и пометить IState как защищенный, чтобы 9X_c# также можно было наследовать от Контроллера.

Controller.cs

public class Controller
{
    protected interface IState
    {
        void Update();
    }

    public class StateBase : IState
    {
        void IState.Update() { OnUpdate(); }
        protected virtual void OnUpdate()
        {
            Console.WriteLine("StateBase.OnUpdate()");
        }
    }

    public Controller()
    {
        IState obj = new PlayerIdleState();
        obj.Update();
    }
}

PlayerIdleState.cs

public class PlayerIdleState: Controller.StateBase
{
    protected override void OnUpdate()
    {
        base.OnUpdate();
        Console.WriteLine("PlayerIdleState.OnUpdate()");
    }
}

И, наконец, пример 9X_patterns того, как протестировать наследование броска 9X_patterns контроллера класса: ControllerTest.cs

class ControllerTest: Controller
{
    public ControllerTest()
    {
        IState testObj = new PlayerIdleState();
        testObj.Update();
    }
}

Надеюсь, я рассмотрю 9X_cxx все случаи и мой ответ был полезен.

15
0

Ответ #5

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

Вы должны иметь возможность выполнять те 9X_object-oriented-design же действия, для которых "друг" используется 9X_design-patterns в C++, используя интерфейсы в C#. Это требует, чтобы 9X_cxx вы явно определяли, какие члены передаются 9X_oo между двумя классами, что является дополнительной 9X_patterns работой, но также может облегчить понимание 9X_c#.net кода.

Если у кого-то есть пример разумного 9X_cpp использования слова «друг», который невозможно 9X_cpp смоделировать с помощью интерфейсов, поделитесь 9X_c++ им! Я хотел бы лучше понять разницу между 9X_oop C++ и C#.

13
2

  • Проблема с интерфейсным подходом * замены 'Friend' * заключается в том, что объект предоставляет интерфейс, это означает, что любой может преобразовать объект в этот интерфейс и иметь доступ к методам! Привязк ...

Ответ #6

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

С помощью friend дизайнер C++ имеет точный контроль 9X_c# над тем, кому доступны закрытые * члены. Но 9X_patterns он вынужден разоблачить каждого из закрытых 9X_friend членов.

С помощью internal дизайнер C# имеет точный 9X_visual-c# контроль над набором закрытых членов, которые 9X_csharp он раскрывает. Очевидно, он может раскрыть 9X_design-patterns только одного закрытого члена. Но он будет 9X_oop доступен для всех классов в сборке.

Обычно 9X_c-sharp разработчик желает предоставить только несколько 9X_pattern частных методов избранным нескольким другим 9X_oop классам. Например, в шаблоне фабрики классов 9X_design-patterns может быть желательно, чтобы экземпляр класса 9X_oops C1 создавался только фабрикой классов CF1. Следовательно, класс 9X_cpp C1 может иметь защищенный конструктор и 9X_oops фабрику дружественных классов CF1.

Как видите, у 9X_csharp нас есть два измерения, по которым инкапсуляция 9X_c#.net может быть нарушена. friend нарушает его по одному 9X_patterns измерению, internal - по другому. Какой из них является 9X_cpp более серьезным нарушением концепции инкапсуляции? Тяжело 9X_oops сказать. Но было бы неплохо иметь в наличии 9X_oop и friend, и internal. Кроме того, хорошим дополнением 9X_visual-c# к этим двум будет третий тип ключевого слова, который 9X_c-sharp будет использоваться для каждого элемента 9X_friend (например, internal) и указывает целевой класс (например, friend).

* Для 9X_patterns краткости я буду использовать «частный» вместо 9X_oo «частный и / или защищенный».

- Ник

13
0

Ответ #7

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

Вы можете приблизиться к "другу" C++ с 9X_oops помощью ключевого слова C# "internal".

8
2

  • @Ash: вам нужно привыкнуть к этому, но как только вы увидите сборки как фундаментальный строительный блок ваших приложений, `internal` приобретает гораздо больший смысл и ...

Ответ #8

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

Friend очень полезен при написании модульного 9X_cpp теста.

Хотя это приводит к небольшому загрязнению 9X_c-sharp объявления вашего класса, это также является 9X_oo напоминанием компилятора о том, какие тесты 9X_c# на самом деле могут заботиться о внутреннем 9X_visual-c# состоянии класса.

Я нашел очень полезную 9X_oo и понятную идиому, когда у меня есть фабричные 9X_design-pattern классы, что делает их друзьями создаваемых 9X_patterns ими элементов, имеющих защищенный конструктор. В 9X_friend частности, это было тогда, когда у меня 9X_c#.net была одна фабрика, отвечающая за создание 9X_csharp соответствующих объектов рендеринга для 9X_cpp объектов составителя отчетов, рендеринг 9X_c-sharp в заданной среде. В этом случае у вас есть 9X_friend единая точка знаний о взаимосвязи между 9X_object-oriented-design классами составителей отчетов (такими как 9X_c-sharp блоки изображений, полосы макета, заголовки 9X_pattern страниц и т. Д.) И соответствующими им объектами 9X_pattern рендеринга.

8
0

Ответ #9

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

В C# отсутствует ключевое слово "friend" по 9X_oops той же причине, по которой отсутствует детерминированное 9X_design-pattern уничтожение. Изменение условностей заставляет 9X_object-oriented-design людей чувствовать себя умными, как будто 9X_pattern их новые пути лучше чужих старых. Все дело 9X_patterns в гордости.

Сказать, что «классы друзей - это 9X_c++ плохо», так же недальновидно, как и другие 9X_oops неквалифицированные утверждения, такие как 9X_oops «не используйте gotos» или «Linux лучше, чем 9X_c++ Windows».

Ключевое слово "friend" в сочетании 9X_c++ с прокси-классом - отличный способ предоставить 9X_patterns только определенные части класса конкретному другому 9X_oo классу (классам). Прокси-класс может выступать 9X_patterns в качестве надежного барьера против всех 9X_oo других классов. «public» не допускает такой 9X_design-patterns таргетинга, а использование «protected» для 9X_oo получения эффекта с наследованием неудобно, если 9X_visual-c# на самом деле нет концептуальных отношений 9X_object-oriented типа «is».

8
2

  • @Edward Robertson Детерминированное разрушение не требует време ...

Ответ #10

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

На самом деле это не проблема C#. Это фундаментальное 9X_cpp ограничение в IL. C# ограничен этим, как 9X_oops и любой другой язык .Net, который стремится 9X_design-patterns быть проверяемым. Это ограничение также 9X_c#.net включает управляемые классы, определенные 9X_oo в C++ / CLI (Spec section 20.5).

При этом я думаю, что у Нельсона 9X_cxx есть хорошее объяснение, почему это плохо.

7
1

  • -1. «друг» - неплохая вещь; напротив, он намного лучше, чем «внутренний». А объяснение Нельсона ...

Ответ #11

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

Перестаньте оправдываться за это ограничение. друг 9X_patterns плохой, а внутренний хороший? это одно и 9X_c#.net то же, только этот друг дает вам более точный 9X_oop контроль над тем, кому разрешен доступ, а 9X_gof кому нет.

Это необходимо для реализации парадигмы 9X_cxx инкапсуляции? так что вам нужно написать 9X_c-sharp методы доступа, и что теперь? как вы должны 9X_patterns запретить всем (кроме методов класса B) вызывать 9X_friend эти методы? вы не можете, потому что вы 9X_oop тоже не можете контролировать это из-за 9X_gof отсутствия «друга».

Ни один язык программирования 9X_c-sharp не совершенен. C# - один из лучших языков, которые 9X_object-oriented я видел, но глупые оправдания отсутствующих 9X_design-patterns функций никому не помогают. В C++ я скучаю 9X_c# по простой системе событий / делегатов, отражению 9X_oop (+ автоматическая де / сериализация) и foreach, но 9X_visual-c# в C# я скучаю по перегрузке оператора (да, продолжайте 9X_patterns говорить мне, что вам это не нужно), параметрам 9X_patterns по умолчанию, константе это невозможно обойти, множественное 9X_csharp наследование (да, продолжайте говорить мне, что 9X_c#.net оно вам не нужно, и интерфейсы были достаточной 9X_design-patterns заменой) и возможность принять решение об 9X_friend удалении экземпляра из памяти (нет, это 9X_c#.net не так уж плохо, если вы не являетесь ремесленник)

4
0

Ответ #12

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

Я отвечу только на вопрос «Как?»

Здесь так много ответов, однако я хотел 9X_c-sharp бы предложить своего рода «шаблон проектирования» для 9X_c-sharp достижения этой функции. Я буду использовать 9X_c#.net простой языковой механизм, который включает:

  • Интерфейсы
  • Вложенный класс

Например, у 9X_patterns нас есть 2 основных класса: Студент и Университет. У 9X_object-oriented студента есть средний академический балл, доступ 9X_c-sharp к которому имеет только университет. Вот 9X_friend код:

public interface IStudentFriend
{
    Student Stu { get; set; }
    double GetGPS();
}

public class Student
{
    // this is private member that I expose to friend only
    double GPS { get; set; }
    public string Name { get; set; }

    PrivateData privateData;

    public Student(string name, double gps) => (GPS, Name, privateData) = (gps, name, new PrivateData(this);

    // No one can instantiate this class, but Student
    // Calling it is possible via the IStudentFriend interface
    class PrivateData : IStudentFriend
    {
        public Student Stu { get; set; }

        public PrivateData(Student stu) => Stu = stu;
        public double GetGPS() => Stu.GPS;
    }

    // This is how I "mark" who is Students "friend"
    public void RegisterFriend(University friend) => friend.Register(privateData);
}

public class University
{
    var studentsFriends = new List();

    public void Register(IStudentFriend friendMethod) => studentsFriends.Add(friendMethod);

    public void PrintAllStudentsGPS()
    {
        foreach (var stu in studentsFriends)
            Console.WriteLine($"{stu.Stu.Name}: stu.GetGPS()");
    }
}

public static void Main(string[] args)
{
    var Technion = new University();
    var Alex     = new Student("Alex", 98);
    var Jo       = new Student("Jo", 91);

    Alex.RegisterFriend(Technion);
    Jo.RegisterFriend(Technion);
    Technion.PrintAllStudentsGPS();

    Console.ReadLine();
}

3
0

Ответ #13

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

Начиная с .Net 3 существует InternalsVisibleToAttribute, но 9X_oo я подозреваю, что они добавили его только 9X_c# для обслуживания тестовых сборок после появления 9X_design-patterns модульного тестирования. Я не вижу многих 9X_c-sharp других причин для его использования.

Он работает 9X_c#.net на уровне сборки, но выполняет ту работу, в 9X_design-patterns которой внутренний - нет; то есть там, где 9X_patterns вы хотите распространить сборку, но хотите, чтобы 9X_pattern другая нераспределенная сборка имела привилегированный 9X_c#.net доступ к ней.

Совершенно справедливо они 9X_object-oriented требуют, чтобы у дружественной сборки был 9X_design-pattern сильный ключ, чтобы никто не создал воображаемого 9X_design-patterns друга вместе с вашей защищенной сборкой.

2
0

Ответ #14

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

Я прочитал много умных комментариев о ключевом 9X_c++ слове "friend", и я согласен, что это полезная 9X_c#.net вещь, но я думаю, что какое "внутреннее" ключевое 9X_oo слово менее полезно, и оба они все еще плохи 9X_cpp для чистого объектно-ориентированного программирования.

Что 9X_oop у нас есть? (говоря о «друге» я также говорю 9X_object-oriented о «внутреннем»)

  • делает ли код менее чистым с точки зрения "друга"?
  • да;

  • не делает ли код лучше 9X_pattern с помощью слова "друг"?

  • нет, нам все еще нужно установить некоторые частные отношения между классами, и мы сможем это сделать, только если нарушим нашу красивую инкапсуляцию, так что это тоже нехорошо, я могу сказать, что это даже хуже, чем использование слова "друг" .

Использование друга 9X_oops создает некоторые локальные проблемы, а 9X_cxx неиспользование его создает проблемы для 9X_csharp пользователей библиотеки кода.

Общее хорошее 9X_c-sharp решение для языка программирования я вижу 9X_oop следующим образом:

// c++ style
class Foo {
  public_for Bar:
    void addBar(Bar *bar) { }
  public:
  private:
  protected:
};

// c#
class Foo {
    public_for Bar void addBar(Bar bar) { }
}

Что вы думаете об этом? Я 9X_design-patterns думаю, что это наиболее распространенное 9X_design-pattern и чисто объектно-ориентированное решение. Вы 9X_cxx можете открыть доступ к любому выбранному 9X_patterns вами методу для любого класса.

2
0

Ответ #15

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

Я подозреваю, что это как-то связано с моделью 9X_cpp компиляции C# - построением IL JIT-компиляции 9X_c#.net во время выполнения. то есть: по той же 9X_oop причине, по которой универсальные шаблоны 9X_csharp C# фундаментально отличаются от универсальных 9X_design-patterns шаблонов C++.

1
0

Ответ #16

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

вы можете оставить его приватным и использовать 9X_friend отражение для вызова функций. Среда тестирования 9X_csharp может сделать это, если вы попросите его 9X_oo протестировать частную функцию

1
0

Ответ #17

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

Раньше я регулярно использовал friend и 9X_oo не думаю, что это нарушение ООП или признак 9X_pattern какой-либо ошибки в дизайне. Есть несколько 9X_object-oriented мест, где это наиболее эффективное средство 9X_c# достижения нужного результата с наименьшим 9X_friend количеством кода.

Одним из конкретных примеров 9X_object-oriented-design является создание интерфейсных сборок, которые 9X_cpp обеспечивают коммуникационный интерфейс 9X_visual-c# для некоторого другого программного обеспечения. Как 9X_design-pattern правило, существует несколько тяжелых классов, которые 9X_object-oriented обрабатывают сложность протокола и особенности 9X_cpp однорангового узла и обеспечивают относительно 9X_c# простую модель подключения / чтения / записи 9X_visual-c# / пересылки / отключения, включающую передачу 9X_pattern сообщений и уведомлений между клиентским 9X_c# приложением и сборкой. Эти сообщения / уведомления 9X_object-oriented нужно обернуть в классы. Атрибуты обычно 9X_oops должны управляться программным обеспечением 9X_visual-c# протокола, поскольку оно является их создателем, но 9X_csharp многие данные должны оставаться доступными 9X_c-sharp только для чтения для внешнего мира.

Просто 9X_cpp глупо заявлять, что это нарушение ООП для 9X_c#.net класса протокола / "создателя", чтобы иметь 9X_object-oriented личный доступ ко всем созданным классам 9X_object-oriented-design - класс-создатель должен был изменять каждый 9X_gof бит данных на пути вверх. Что я считаю наиболее 9X_c# важным, так это свести к минимуму все лишние 9X_c# строки кода BS, к которым обычно приводит 9X_c++ модель «ООП ради ООП». Дополнительные спагетти 9X_c++ порождают больше ошибок.

Знают ли люди, что 9X_object-oriented-design ключевое слово internal можно применять 9X_gof на уровне атрибутов, свойств и методов? Это 9X_c# касается не только объявления класса верхнего 9X_c#.net уровня (хотя большинство примеров, кажется, это 9X_design-pattern демонстрируют).

Если у вас есть класс C++, в 9X_design-patterns котором используется ключевое слово friend, и 9X_c# вы хотите имитировать это в классе C#: 1. объявить 9X_pattern класс C# общедоступным 2. объявить все атрибуты 9X_c-sharp / свойства / методы, которые защищены в 9X_design-patterns C++ и, следовательно, доступны друзьям, как 9X_gof внутренние в C#. 3. создать свойства только 9X_oop для чтения для общего доступа ко всем внутренним 9X_oo атрибутам и свойствам

Я согласен, что это 9X_pattern не на 100% то же самое, что и friend, и 9X_oo модульный тест - очень ценный пример необходимости 9X_gof чего-то вроде друга (как и код журналирования 9X_cpp анализатора протокола). Однако internal 9X_oops обеспечивает доступ к классам, которые вы 9X_cxx хотите использовать, а [InternalVisibleTo()] обрабатывает 9X_patterns все остальное - похоже, он был создан специально 9X_pattern для модульного тестирования.

Что касается 9X_object-oriented друга, «быть лучше, потому что вы можете 9X_oo явно контролировать, какие классы имеют 9X_oop доступ» - что, черт возьми, группа подозрительных 9X_c#.net злых классов делает в одной и той же сборке 9X_visual-c# в первую очередь? Разбивайте сборки на разделы!

1
0

Ответ #18

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

Дружбу можно смоделировать, разделив интерфейсы 9X_c-sharp и реализации. Идея такова: «Требовать конкретный экземпляр, но ограничить доступ для построения этого экземпляра».

Например

interface IFriend { }

class Friend : IFriend
{
    public static IFriend New() { return new Friend(); }
    private Friend() { }

    private void CallTheBody() 
    {  
        var body = new Body();
        body.ItsMeYourFriend(this);
    }
}

class Body
{ 
    public void ItsMeYourFriend(Friend onlyAccess) { }
}

Несмотря 9X_oop на то, что ItsMeYourFriend() является общедоступным, только 9X_cpp класс Friend может получить к нему доступ, поскольку 9X_csharp никто другой не может получить конкретный 9X_oop экземпляр класса Friend. У него есть частный конструктор, а 9X_design-patterns фабричный метод New() возвращает интерфейс.

Подробности 9X_friend см. в моей статье Friends and internal interface members at no cost with coding to interfaces.

1
0

Ответ #19

Ответ на вопрос: Почему C# не предоставляет ключевое слово friend в стиле C++?

Некоторые полагают, что с помощью друга 9X_design-patterns все может выйти из-под контроля. Я бы согласился, но 9X_oops это не умаляет его полезности. Я не уверен, что 9X_visual-c# друг обязательно вредит парадигме объектно-ориентированного 9X_friend программирования не больше, чем публикация 9X_gof всех членов вашего класса. Конечно, язык 9X_c++ позволит вам сделать всех ваших участников 9X_oop общедоступными, но это дисциплинированный 9X_friend программист, который избегает такого типа 9X_oop шаблона проектирования. Точно так же дисциплинированный 9X_csharp программист прибегнет к использованию друга 9X_c++ для конкретных случаев, когда это имеет 9X_cxx смысл. Я чувствую, что в некоторых случаях 9X_csharp внутренняя экспозиция слишком велика. Зачем 9X_c-sharp открывать класс или метод для всего в сборке?

У 9X_object-oriented-design меня есть страница ASP.NET, которая наследует 9X_oops мою собственную базовую страницу, которая, в 9X_patterns свою очередь, наследует System.Web.UI.Page. На 9X_cpp этой странице у меня есть код, который обрабатывает 9X_design-patterns отчеты об ошибках конечного пользователя 9X_patterns для приложения в защищенном методе

ReportError("Uh Oh!");

Теперь 9X_oops у меня есть пользовательский элемент управления, содержащийся 9X_oo на странице. Я хочу, чтобы пользовательский 9X_c-sharp элемент управления мог вызывать методы сообщения 9X_cxx об ошибках на странице.

MyBasePage bp = Page as MyBasePage;
bp.ReportError("Uh Oh");

Этого не может быть, если 9X_friend метод ReportError защищен. Я могу сделать 9X_object-oriented-design его внутренним, но он доступен для любого 9X_friend кода сборки. Я просто хочу, чтобы он был 9X_c#.net доступен для элементов пользовательского 9X_oops интерфейса, которые являются частью текущей 9X_visual-c# страницы (включая дочерние элементы управления). В 9X_oo частности, я хочу, чтобы мой базовый класс 9X_cpp управления определял те же самые методы 9X_patterns сообщения об ошибках и просто вызывал методы 9X_csharp на базовой странице.

protected void ReportError(string str) {
    MyBasePage bp = Page as MyBasePage;
    bp.ReportError(str);
}

Я считаю, что что-то 9X_design-patterns вроде друга может быть полезно и реализовано 9X_c++ на языке, не делая язык менее «объектно-ориентированным», например, в 9X_c# виде атрибутов, так что вы можете иметь 9X_cxx классы или методы в качестве друзей для 9X_csharp определенных классов или методов, что позволяет 9X_oop разработчику чтобы обеспечить очень конкретный 9X_c++ доступ. Возможно что-то вроде ... (псевдокод)

[Friend(B)]
class A {

    AMethod() { }

    [Friend(C)]
    ACMethod() { }
}

class B {
    BMethod() { A.AMethod() }
}

class C {
    CMethod() { A.ACMethod() }
}

В 9X_oo случае с моим предыдущим примером, возможно, есть 9X_design-pattern что-то вроде следующего (можно поспорить 9X_patterns с семантикой, но я просто пытаюсь донести 9X_friend идею):

class BasePage {

    [Friend(BaseControl.ReportError(string)]
    protected void ReportError(string str) { }
}

class BaseControl {
    protected void ReportError(string str) {
        MyBasePage bp = Page as MyBasePage;
        bp.ReportError(str);
    }
}

На мой взгляд, концепция друга не 9X_cpp представляет большего риска, чем публикация 9X_c# вещей или создание общедоступных методов 9X_c++ или свойств для доступа к членам. Во всяком 9X_patterns случае, друг допускает другой уровень детализации 9X_cpp в доступности данных и позволяет вам сузить 9X_patterns эту доступность, а не расширять ее за счет 9X_oops внутренних или общедоступных.

1
0