КАТЕГОРИИ:
АстрономияБиологияГеографияДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРиторикаСоциологияСпортСтроительствоТехнологияФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника
|
Упрощенный синтаксис № 2: не нужно определять метод обратного вызоваВ приведенном выше коде имя метода обратного вызова, SomeAsyncTask, передается методу QueueUserWorkltem класса ThreadPool. С# позволяет встраивать реализацию метода обратного вызова непосредственно в код, а не в сам метод. Например, приведенный выше код можно переписать так. internal sealed class AClass { public static void CallbackWithoutNewingADelegateObject() { ThreadPool.QueueUserWorkItem(delegate(Object obj) { Console.WriteLine(obj); }, 5); } }
Заметьте: первый «параметр» метода QueueUserWorkltem представляет собой блок кода! Обнаружив ключевое слово delegate в месте, где ожидается ссылка на объект- делегат, компилятор С# автоматически определяет в классе новый закрытый метод (здесь это класс AClass). Этот новый метод называют анонимным из-за того, что компилятор создает имя метода автоматически и обычно вы даже никогда не узнаете его имя. Однако можно прибегнуть к ILDasm.exe, чтобы изучить сгенерированный компилятором код. После компиляции приведенного выше кода с помощью ILDasm.exe я увидел, что компилятор С# решил назвать этот метод <CallbackWithoutNewingADelegateObject>b__0. Но будьте осторожны: никогда не стоит рассчитывать на то, что компилятор создаст именно такое имя метода, потому что в следующей версии компилятора С# алгоритм генерации имени метода может измениться. Используя ILDasm.exe, также можно заметить, что компилятор С# применяет к этому методу атрибут SystemRuntime.CompilerServices.CompilerGeneratedAttribute для указания того, что метод создан компилятором, а не программистом. Код из «параметра» размещается в сгенерированном компилятором методе. Примечание Число операторов или их типов, которые можно использовать в коде обратного вызова (анонимном методе), не ограничено. Однако при создании анонимного метода никак нельзя применить к методу нестандартный (пользовательский) атрибут. Более того — по отношению к методу нельзя применить никаких модификаторов метода (например, unsafe). Сгенерированные компилятором анонимные методы практически всегда закрыты, а метод — статический или нестатический, в зависимости от того, к каким членам экземпляра обращается метод. Так что нет никакой нужды применять к методу такие модификаторы, как public, protected, internal, virtual, sealed, override и abstract. Наконец, при компиляции приведенного выше кода компилятор C# перепишет код примерно так: internal sealed class AClass { // Это закрытое поле создается для кеширования объекта-делегата. // Преимущество: CallbackWithoutNewingADelegateObject не будет создавать // новый объект при каждом вызове. // Недостаток: объект в кеше никогда не убирается сборщиком мусора.
[CompilerGenеrated] private static WaitCallback <>9__CachedAnonymousMethodDelegate1; public static void CallbackWithoutNewingADelegateObject() { if (<>9__CachedAnonymousMethodDelegate1 == null) { // При первом вызове объект-делегат создается и кешируется. <>9__CachedAnonymousMethodDelegate1 = new WaitCallback(<CallbackWithoutNewingADelegateObject>b__0); } ThreadPool.QueueUserWorkItem(<>9__CachedAnonymousMethodDelegate1, 5); }
[CompilerGenеrated] private static void <CallbackWithoutNewingADelegateObject>b__0(Object obj) { Console.WriteLine(obj); } } Прототип анонимного метода должен соответствовать типу делегата WaitCallback: возвращать void и принимать параметр Object. Однако я создавал анонимный метод, поэтому определил имя параметра, разместив (Object obj) после ключевого слова delegate. Анонимный метод объявляется закрытым; это запрещает любому коду, за исключением кода типа, доступ к методу (хотя отражение позволит узнать, что метод существует). Заметьте также, что анонимный метод определен как статический, потому что код не обращается ни к каким членам экземпляра (да и не сможет этого сделать, так как CallbackWithoutNewingADelegate-Object — сам по себе статический метод). Однако код может сослаться на любые определенные в классе статические поля или статические методы. Вот пример: internal sealed class AClass { private static String sm_name; // Статическое поле. public static void CallbackWithoutNewingADelegateObject() { ThreadPool.QueueUserWorkItem( // Код обратного вызова может ссылаться на статические члены. delegate(Object obj) { Console.WriteLine(sm_name + ": " + obj); }, 5 ); } } Если бы метод CallbackWithoutNewingADelegateObject не был статическим, код анонимного метода мог бы содержать ссылки на члены экземпляра. Но даже в отсутствие в коде ссылок на члены экземпляра компилятор создаст статический анонимный метод, так как он эффективнее, чем экземплярный метод, потому что дополнительный параметр this не нужен. Но, если код анонимного метода действительно ссылается на член экземпляра, компилятор создаст нестатический анонимный метод: internal sealed class AClass { private String m_name; // Зкземплярное поле. // Экземплярный метод. public void CallbackWithoutNewingADelegateObject() { ThreadPool.QueueUserWorkItem( // Код обратного вызова может ссылаться на члены экземпляра. delegate(Object obj) { Console.WriteLine(m_name + ": " + obj); }, 5 ); } }
|