Почему лямбда-выражения не «интернированы»?

Строки являются ссылочными типами, но они неизменяемы. Это позволяет компилятору интернировать их; везде, где встречается один и тот же строковый литерал, можно ссылаться на один и тот же объект.

Делегаты также являются неизменяемыми ссылочными типами. (Добавление метода к многоадресному делегату с использованием оператора + = составляет присваивание ; это не изменчивость.) И, подобно строкам, существует «буквальный» способ представления делегата в коде, используя лямбда-выражение, например:

Func func = () => 5;

Правая часть этого оператора - это выражение с типом Func ; но нигде я не вызываю явно конструктор Func (при этом не происходит неявного преобразования). Поэтому я рассматриваю это как литерал . Я ошибаюсь в моем определении «буквального» здесь?

Тем не менее, вот мой вопрос. Если у меня есть две переменные, скажем, для типа Func , и я назначаю им одинаковые лямбда-выражения:

Func x = () => 5;
Func y = () => 5;

... что мешает компилятору рассматривать их как одинаковые Func объект?

Я спрашиваю, потому что в разделе 6.5.1 спецификации языка C # 4.0 четко сказано:

Преобразования семантически идентичных но нигде я не вызываю явно конструктор Func (при этом не происходит неявного преобразования). Поэтому я рассматриваю это как литерал . Я ошибаюсь в моем определении «буквального» здесь?

Тем не менее, вот мой вопрос. Если у меня есть две переменные, скажем, для типа Func , и я назначаю им одинаковые лямбда-выражения:

Func x = () => 5;
Func y = () => 5;

... что мешает компилятору рассматривать их как одинаковые Func объект?

Я спрашиваю, потому что в разделе 6.5.1 спецификации языка C # 4.0 четко сказано:

Преобразования семантически идентичных но нигде я не вызываю явно конструктор Func (при этом не происходит неявного преобразования). Поэтому я рассматриваю это как литерал . Я ошибаюсь в моем определении «буквального» здесь?

Тем не менее, вот мой вопрос. Если у меня есть две переменные, скажем, для типа Func , и я назначаю им одинаковые лямбда-выражения:

Func x = () => 5;
Func y = () => 5;

... что мешает компилятору рассматривать их как одинаковые Func объект?

Я спрашиваю, потому что в разделе 6.5.1 спецификации языка C # 4.0 четко сказано:

Преобразования семантически идентичных Я ошибаюсь в моем определении «буквального» здесь?

Тем не менее, вот мой вопрос. Если у меня есть две переменные, скажем, для типа Func , и я назначаю им одинаковые лямбда-выражения:

Func x = () => 5;
Func y = () => 5;

... что мешает компилятору рассматривать их как одинаковые Func объект?

Я спрашиваю, потому что в разделе 6.5.1 спецификации языка C # 4.0 четко сказано:

Преобразования семантически идентичных Я ошибаюсь в моем определении «буквального» здесь?

Тем не менее, вот мой вопрос. Если у меня есть две переменные, скажем, для типа Func , и я назначаю им одинаковые лямбда-выражения:

Func x = () => 5;
Func y = () => 5;

... что мешает компилятору рассматривать их как одинаковые Func объект?

Я спрашиваю, потому что в разделе 6.5.1 спецификации языка C # 4.0 четко сказано:

Преобразования семантически идентичных анонимные функции с такими же (возможно, пустой) набор захваченных внешних экземпляры переменных к тому же типы делегатов разрешены (но не требуется), чтобы вернуть того же делегата пример. Термин семантически идентичный здесь означает, что выполнение анонимных функций будет во всех случаях производить одинаковые эффекты приведены те же аргументы.

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

class EventSender
{
    public event EventHandler Event;
    public void Send()
    {
        EventHandler handler = this.Event;
        if (handler != null) { handler(this, EventArgs.Empty); }
    }
}

class Program
{
    static string _message = "Hello, world!";

    static void Main()
    {
        var sender = new EventSender();
        sender.Event += (obj, args) => Console.WriteLine(_message);
        sender.Send();

        // Unless I'm mistaken, this lambda expression is semantically identical
        // to the one above. However, the handler is not removed, indicating
        // that a different delegate instance is constructed.
        sender.Event -= (obj, args) => Console.WriteLine(_message);

        // This prints "Hello, world!" again.
        sender.Send();
    }
}

Есть ли причина, по которой такое поведение - один экземпляр делегата для семантически идентичных анонимных методов - не реализовано?

15
задан Dan Tao 26 January 2011 в 17:33
поделиться