Преобразовать этого делегата в анонимный метод или лямбду - PullRequest
21 голосов
/ 12 сентября 2008

Я новичок во всех анонимных функциях и мне нужна помощь. Я получил следующее на работу:

public void FakeSaveWithMessage(Transaction t)
{
    t.Message = "I drink goats blood";
}

public delegate void FakeSave(Transaction t);

public void SampleTestFunction()
{
    Expect.Call(delegate { _dao.Save(t); }).Do(new FakeSave(FakeSaveWithMessage));
}

Но это совершенно безобразно, и я хотел бы, чтобы внутри Do был анонимный метод или даже лямбда, если это возможно. Я попробовал:

Expect.Call(delegate { _dao.Save(t); }).Do(delegate(Transaction t2) { t2.Message = "I drink goats blood"; });

и

Expect.Call(delegate { _dao.Save(t); }).Do(delegate { t.Message = "I drink goats blood"; });

но это дает мне

Невозможно преобразовать анонимный метод в тип «System.Delegate», поскольку он не является типом делегата ** ошибки компиляции.

Что я делаю не так?


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

public delegate void FakeSave(Transaction t);

Expect.Call(delegate { _dao.Save(t); }).Do( new FakeSave(delegate(Transaction t2) { t.Message = expected_msg; }));

Ответы [ 4 ]

27 голосов
/ 12 сентября 2008

Это хорошо известное сообщение об ошибке. Для более подробного обсуждения перейдите по ссылке ниже.

http://staceyw1.wordpress.com/2007/12/22/they-are-anonymous-methods-not-anonymous-delegates/

В основном вам просто нужно поставить приведение перед вашим анонимным делегатом (вашим лямбда-выражением).

В случае, если ссылка отключится, вот копия сообщения:

Это анонимные методы, а не Анонимные делегаты.
Опубликовано 22 декабря 2007 г. автором staceyw1

Это не просто разговор, потому что мы хотим быть трудными Это помогает нам причина того, что именно происходит. Чтобы было ясно, нет * такой вещи как анонимный делегат. Они не существует (пока нет). Они "Аноним Методы "- период. Важно, как мы думаем о них и как мы говорим о их. Давайте посмотрим на оператор анонимного метода "делегат () {…} ". Это на самом деле два разных операции и когда мы думаем об этом таким образом, мы никогда не будем путать снова. Первым делом компилятор делает это создать анонимный метод под одеялом, используя выведенный подпись делегата как метод подпись. Не правильно говорить метод "безымянный", потому что он есть имя и компилятор назначает это. Это просто скрыто от нормальный вид. Следующее, что он делает это создать объект делегата из требуемый тип, чтобы обернуть метод. это называется выводом делегата и может быть источником этой путаницы. За чтобы это работало, компилятор должен быть в состоянии выяснить (то есть сделать вывод), что тип делегата, который он создаст. Она имеет быть известным конкретным типом. Позволять написать код, чтобы понять, почему.

private void MyMethod()
{
}

Не компилируется:

1) Delegate d = delegate() { };                       // Cannot convert anonymous method to type ‘System.Delegate’ because it is not a delegate type
2) Delegate d2 = MyMethod;                         // Cannot convert method group ‘MyMethod’ to non-delegate type ‘System.Delegate’
3) Delegate d3 = (WaitCallback)MyMethod;   // No overload for ‘MyMethod’ matches delegate ‘System.Threading.WaitCallback’

Строка 1 не компилируется, потому что Компилятор не может вывести любой делегат тип. Это может ясно видеть подпись мы желаем, но нет конкретного тип делегата, который может видеть компилятор. Это может создать анонимный тип Тип делегата для нас, но это не так работать так Строка 2 не скомпилировать по аналогичной причине. Четное хотя компилятор знает метод подпись, мы не даем тип делегата, и это не просто происходит выбрать тот, который будет работать (не какие побочные эффекты, которые могли бы иметь). Строка 3 не работает, потому что мы намеренно не соответствовали методу подпись с делегатом, имеющим другая подпись (как WaitCallback берет и возражает).

Компиляции:

4) Delegate d4 = (MethodInvoker)MyMethod;  // Works because we cast to a delegate type of the same signature.
5) Delegate d5 = (Action)delegate { };              // Works for same reason as d4.
6) Action d6 = MyMethod;                                // Delegate inference at work here. New Action delegate is created and assigned.

Напротив, эти работы. Линия 1 работает потому что мы говорим компилятору, что тип делегата для использования, и они совпадают, так работает Строка 5 работает для та же самая причина. Обратите внимание, что мы использовали специальные Форма «делегат» без слов. Компилятор выводит метод подпись от актеров и создает анонимный метод с тем же подпись в качестве предполагаемого делегата тип. Строка 6 работает, потому что MyMethod () и Action используют одно и то же подпись.

Надеюсь, это поможет.

Также см .: http://msdn.microsoft.com/msdnmag/issues/04/05/C20/

3 голосов
/ 12 сентября 2008

Что сказал Марк.

Проблема в том, что Do принимает параметр Delegate. Компилятор не может преобразовать анонимные методы в Delegate, только «тип делегата», то есть конкретный тип, производный от Delegate.

Если бы эта функция Do имела перегрузки Action <>, Action <,> ... и т. Д., Преобразование не понадобилось бы.

1 голос
/ 12 сентября 2008

Проблема не в определении вашего делегата, а в том, что параметр метода Do () имеет тип System.Delegate, а сгенерированный компилятором тип делегата (FakeSave) неявным образом не преобразуется в System.Delegate.

Попробуйте добавить приведение перед вашим анонимным делегатом:

Expect.Call(delegate { _dao.Save(t); }).Do((Delegate)delegate { t.Message = "I drink goats blood"; });
0 голосов
/ 12 сентября 2008

Попробуйте что-то вроде:

Expect.Call(delegate { _dao.Save(t); }).Do(new EventHandler(delegate(Transaction t2) { t2.CheckInInfo.CheckInMessage = "I drink goats blood"; }));

Обратите внимание на добавленный EventHandler вокруг делегата.

РЕДАКТИРОВАТЬ: может не работать, так как сигнатуры функций EventHandler и делегата не совпадают ... Решение, которое вы добавили внизу вашего вопроса, может быть единственным.

Кроме того, вы можете создать универсальный тип делегата:

public delegate void UnitTestingDelegate<T>(T thing);

Так что делегат не является специфичным для транзакции.

...