2008-09-12 1 views
21

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

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)); 
} 

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

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», потому что это не тип делегата ** ошибки компиляции ,

Что я делаю неправильно?


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

public delegate void FakeSave(Transaction t); 

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

ответ

27

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

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

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

В случае связь когда-либо идет вниз, вот копия поста:

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

Это не просто языцех, потому что мы хотим быть трудно. Это помогает нам узнать, что именно происходит. Чтобы быть ясным, нет такой вещи как анонимный делегат. Они не существуют (еще не). Они "Anonymous Методы" - период. Неважно, как мы думаем о них и как мы говорим о них .Давайте рассмотрим заявление анонимного метода "delegate() {...}". Это фактически две разные операции , и когда мы думаем об этом таким образом, мы больше не будем путать . Первое, что делает компилятор , - это создать анонимный метод под обложками, используя inferred подпись делегата как метод подпись. Неверно сказать метод «неназванный», потому что он имеет имя и компилятор присваивает его. Он просто скрыт от обычного вида. Следующее, что он делает , создает объект-делегат требуемого типа для переноса метода. Этот называется делегатским выводом и может быть источником этой путаницы. Для это для работы, компилятор должен быть , способный вычислить (то есть вывести), что тип делегата, который он создаст. Он имеет , чтобы быть известным бетонным типом. Пусть напишите код, чтобы узнать почему.

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() и Действие используют такую ​​же подпись .

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

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

+1

Хорошей связи, но я до сих пор не понимаю, почему * * компилятор не бросьте автомагически (как это делает с синтаксисом лямбды) – 2010-12-22 21:12:00

+0

Ссылка не работает. – 2011-04-07 20:54:33

0

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

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

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

EDIT: возможно, не работает, поскольку функции-подписи EventHandler и делегата не совпадают ... Решение, добавленное в нижней части вашего вопроса, может быть единственным способом.

В качестве альтернативы, вы можете создать общий тип делегата:

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

Так что делегат не конкретной сделки.

3

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

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

Если это произошло, то действие <>, действие <,> ... и т. Д. Перегрузки, вам не понадобится приведение.

1

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

Попробуйте добавить бросок в передней части анонимного делегата:

Expect.Call(delegate { _dao.Save(t); }).Do((Delegate)delegate { t.Message = "I drink goats blood"; }); 
Смежные вопросы