Странное поведение с использованием делегатов и лямбда
Как средство введения ленивой оценки форматирования в библиотеке, которую я разрабатываю, я определил делегатов
public delegate string MessageFormatterDelegate(string message, params object[] arguments);
public delegate string MessageFormatterCallback(MessageFormatterDelegate formatterDelegate);
и что-то вроде строк следующего класса
public static class TestClass
{
public static string Evaluate(MessageFormatterCallback formatterCallback)
{
return (formatterCallback(String.Format));
}
}
Однако это ведет себя довольно странно: при запуске из проекта external утверждение
Console.WriteLine(TestClass.Evaluate(message => message("{0},{1},{2}", 1, 2, 3)));
выполняет не компиляцию, сбой при ошибке
Error 1 Delegate 'MessageFormatterDelegate' does not take 4 arguments
а
Console.WriteLine(TestClass.Evaluate((MessageFormatterDelegate message) => message("{0},{1},{2}", 1, 2, 3)));
компилируется и работает без проблем, печатая 1,2,3
в консоли. Почему мне нужно квалифицировать аргумент message
с типом MessageFormatterDelegate
во втором выражении лямбда? Есть ли способ обойти это поведение?
Ответы
Ответ 1
EDIT: Хорошо, теперь у меня есть более короткий пример и обходной путь.
Первый исходный файл, External.cs
:
public delegate string Callback(System.Action<string> x);
Второй исходный файл, Test.cs
:
class Test
{
static void Main()
{
Callback callback = action => action("hello");
}
}
Скомпилировать с помощью:
> csc /target:library External.cs
> csc Test.cs /r:External.cs
Ошибка:
Делегирование "Действие" не принимает 1 аргумент
Временное решение: измените тело метода Main
на:
Callback callback = action => action.Invoke("hello");
... или включить объявление делегата в той же сборке, которая его использует.
Это определенно похоже на ошибку. Когда компилятор знает, что тип foo
является конкретным типом делегирования, тогда foo(arg)
и foo.Invoke(arg)
должны быть эквивалентными.
Будет ли письмо Эриком Липпертом...
Ответ 2
UPDATE:
Исправлена ошибка в С# 5. Извинитесь за неудобства и благодарность за отчет.
Это, кажется, дубликат известной ошибки, описанной здесь:
'Делегат' System.Action 'не принимает 0 аргументов.' Является ли это ошибкой компилятора С# (lambdas + два проекта)?
Подробнее см. мой ответ на этот вопрос.
Здесь также сообщалось:
С# Ошибка Parser на делегате?
Эта ошибка была моей плохой; Прошу прощения за ошибку. Мы попытаемся получить исправление в С# 5.
Если вы думаете, что на самом деле обнаружили другую ошибку, сообщите мне, и мы начнем расследование.
И спасибо за отчет, я ценю это.