ПриМеЧание
При.написании.лямбда-выражений.невозможно.применить.к.сгенерированному.
компилятором.методу.пользовательские.атрибуты.или.модификаторы.(например,.
unsafe) .Впрочем,.обычно.это.не.является.проблемой,.так.как.созданные.компилято-
ром.анонимные.методы.всегда.закрыты .Каждый.такой.метод.является.статическим.
или.нестатическим.в.зависимости.от.того,.будет.ли.он.иметь.доступ.к.каким-либо.
экземплярным.членам .Соответственно,.применять.к.этим.методам.модификаторы.
public,.protected,.internal,.virtual,.sealed,.override.или.abstract.просто.не.требуется
Написанный код компилятор C# переписывает примерно таким образом (ком-
ментарии вставлены мною):
internal sealed class AClass {
// Это закрытое поле создано для кэширования делегата
// Преимущество: CallbackWithoutNewingADelegateObject не будет
// создавать новый объект при каждом вызове
// Недостатки: кэшированные объекты недоступны для сборщика мусора
[CompilerGenerated]
private static WaitCallback <>9__CachedAnonymousMethodDelegate1;
public static void CallbackWithoutNewingADelegateObject() {
if (<>9__CachedAnonymousMethodDelegate1 == null) {
// При первом вызове делегат создается и кэшируется
<>9__CachedAnonymousMethodDelegate1 =
new WaitCallback(b__0);
}
ThreadPool.QueueUserWorkItem(<>9__CachedAnonymousMethodDelegate1, 5);
}
[CompilerGenerated]
private static void b__0(
Object obj) {
Console.WriteLine(obj);
}
}
Лямбда-выражение должно соответствовать сигнатуре делегата
WaitCallback
:
возвращать
void
и принимать параметр типа
Object
. Впрочем, я указал имя пара-
455
Упрощенный.синтаксис.работы.с.делегатами
метра, просто поместив переменную
obj
слева от оператора
=>
. Расположенный
справа от этого оператора метод
Console.WriteLine
действительно возвращает
void
. Если бы расположенное справа выражение не возвращало
void
, сгенериро-
ванный компилятором код просто проигнорировал бы возвращенное значение, ведь
в противном случае не удалось бы соблюсти требования делегата
WaitCallback
.
Также следует отметить, что анонимная функция помечается как
private
; в итоге
доступ к методу остается только у кода, определенного внутри этого же типа (хотя
отражение позволит узнать о существовании метода). Обратите внимание, что
анонимный метод определен как статический. Это связано с отсутствием у кода
доступа к каким-либо членам экземпляра (ведь метод
CallbackWithoutNewingADe
legateObject
сам по себе статический). Впрочем, код может обращаться к любым
определенным в классе статическим полям или методам. Например:
internal sealed class AClass {
private static String sm_name; // Статическое поле
public static void CallbackWithoutNewingADelegateObject() {
ThreadPool.QueueUserWorkItem(
// Код обратного вызова может обращаться к статическим членам
obj =>Console.WriteLine(sm_name+ ": " + obj),
5);
}
}
Не будь метод
CallbackWithoutNewingADelegateObject
статическим, код ано-
нимного метода мог бы содержать ссылки на члены экземпляра. Но даже при от-
сутствии таких ссылок компилятор все равно генерирует статический анонимный
метод, так как он эффективнее экземплярного метода, потому что ему не нужен
дополнительный параметр
this
. Если же в коде анонимного метода наличествуют
ссылки на члены экземпляра, компилятор создает нестатический анонимный метод:
internal sealed class AClass {
private String m_name; // Поле экземпляра
// Метод экземпляра
public void CallbackWithoutNewingADelegateObject() {
ThreadPool.QueueUserWorkItem(
// Код обратного вызова может ссылаться на члены экземпляра
obj => Console.WriteLine(m_name+ ": " + obj),
5);
}
}
Имена аргументов, которые следует передать лямбда-выражению, указываются
слева от оператора
=>
. При этом следует придерживаться правил, которые мы рас-
смотрим на примерах:
// Если делегат не содержит аргументов, используйте круглые скобки
Func f = () => "Jeff";
// Для делегатов с одним и более аргументами
продолжение
456
Do'stlaringiz bilan baham: |