Что означает делегат внутри класса? - PullRequest
2 голосов
/ 17 сентября 2010

Я понимаю делегатов как ярлык для определения класса одним методом, но каково значение bar2 ниже?Это компилируется.Но я не вижу, что будет делать внутренний класс.Я знаю, что что-то упускаю, поэтому я и спрашиваю (это не домашняя работа, я сейчас на работе).

namespace ns2 { public delegate void bar();}
public class foo
{
    private ns2.bar _callback;
    public foo(ns2.bar callback) { _callback = callback; }
    public void baz() { _callback(); }
    public delegate void bar2();
}

Спасибо!

Ответы [ 3 ]

8 голосов
/ 23 сентября 2010

Чтобы добавить к ответам Джона и Джареда, я отмечаю, что единственный раз, когда вы обычно определяете делегата внутри класса, это если он был частной деталью реализации класса. Редко и странно иметь public определение делегата внутри класса.

Например, рассмотрим мой любимый шаблон: абстрактный базовый класс, который может быть расширен только частными вложенными классами, изготовленными на фабриках:

public abstract class Animal
{
    private Animal() { } // prevents subclassing from outside!
    private sealed class Giraffe : Animal { }
    private sealed class Leopard : Animal { }
    public static Animal GetGiraffe( ) { return new Giraffe(); }
    public static Animal GetLeopard( ) { return new Leopard(); }

Предположим, что деталь реализации Animal заключалась в том, что вам нужен делегат от Жирафа до Леопарда:

    private delegate Leopard D(Giraffe g);

Это не может быть открытый класс делегата, поскольку он относится к закрытым типам!

В настоящее время, конечно, вы бы этого даже не сделали. Вы бы использовали Func<Giraffe, Leopard> и все готово.

Следовательно, вложенный тип делегата в значительной степени существует для полноты и обратной совместимости в наши дни; обычно вы бы не использовали его.

7 голосов
/ 17 сентября 2010

Делегаты не являются ярлыками для определения класса одним методом. На самом деле они имеют как минимум 6 методов (Invoke, BeginInvoke, EndInvoke, GetHashCode, Equals, ToString).

Одна из причин, по которой шаблон помещается в тип, заключается в том, чтобы избежать загрязнения глобального пространства имен. Делегат bar2 доступен только через квалифицированную ссылку из foo. Это может быть полезно, если bar2 - это имя, которое имеет несколько допустимых значений, и если поместить его в foo, это обеспечивает необходимый контекст.

6 голосов
/ 17 сентября 2010

Это просто объявление вложенного типа, вот и все.Так как он общедоступный, между объявлением внутри типа и объявлением снаружи почти нет различий.

Другие классы должны будут ссылаться на него через имя содержащего типа (если только у них нет usingдиректива специально для него):

public class OtherClass
{
    private void DoSomething()
    {
        foo.bar2 action = delegate { ... };
        foo f = new foo(action);
        ...
    }
}

Обычно , когда я пишу вложенный тип, он закрытый - это просто вспомогательный класс для содержащего класса;деталь реализации.Конечно, это не обязательно должно быть так, но, по крайней мере, должно быть верно, что вложенный тип не имеет смысла, если только вы не используете некоторый способ использования внешнего класса.Например, это может быть компоновщик для внешнего класса или перечисление, используемое в некоторых параметрах для вызова метода во внешнем классе.

(Кстати, полезно при написании примера кода, подобного этому, следоватьСоглашения об именах .NET даже для метасинтаксических имен, таких как Foo и Bar. Это, например, делает разницу между переменными и типами более понятной.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...