I am new to all the anonymous features and need some help. I have gotten the following to work:
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));
}
But this is totally ugly and I would like to have the inside of the Do to be an anonymous method or even a lambda if it is possible. I tried:
Expect.Call(delegate { _dao.Save(t); }).Do(delegate(Transaction t2) { t2.Message = "I drink goats blood"; });
and
Expect.Call(delegate { _dao.Save(t); }).Do(delegate { t.Message = "I drink goats blood"; });
but these give me
Cannot convert anonymous method to type 'System.Delegate' because it is not a delegate type** compile errors.
What am I doing wrong?
Because of what Mark Ingram posted, seems like the best answer, though nobody's explicitly said it, is to do this:
public delegate void FakeSave(Transaction t);
Expect.Call(delegate { _dao.Save(t); }).Do( new FakeSave(delegate(Transaction t2) { t.Message = expected_msg; }));
That's a well known error message. Check the link below for a more detailed discussion.
http://staceyw1.wordpress.com/2007/12/22/they-are-anonymous-methods-not-anonymous-delegates/
Basically you just need to put a cast in front of your anonymous delegate (your lambda expression).
In case the link ever goes down, here is a copy of the post:
They are Anonymous Methods, not
Anonymous Delegates.
Posted on December 22, 2007 by staceyw1
It is not just a talking point because
we want to be difficult. It helps us
reason about what exactly is going on.
To be clear, there is *no such thing
as an anonymous delegate. They don’t
exist (not yet). They are "Anonymous
Methods" – period. It matters in how
we think of them and how we talk about
them. Lets take a look at the
anonymous method statement "delegate()
{…}". This is actually two different
operations and when we think of it
this way, we will never be confused
again. The first thing the compiler
does is create the anonymous method
under the covers using the inferred
delegate signature as the method
signature. It is not correct to say
the method is "unnamed" because it
does have a name and the compiler
assigns it. It is just hidden from
normal view. The next thing it does
is create a delegate object of the
required type to wrap the method. This
is called delegate inference and can
be the source of this confusion. For
this to work, the compiler must be
able to figure out (i.e. infer) what
delegate type it will create. It has
to be a known concrete type. Let
write some code to see why.
private void MyMethod()
{
}
Does not compile:
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’
Line 1 does not compile because the
compiler can not infer any delegate
type. It can plainly see the signature
we desire, but there is no concrete
delegate type the compiler can see.
It could create an anonymous type of
type delegate for us, but it does not
work like that. Line 2 does not
compile for a similar reason. Even
though the compiler knows the method
signature, we are not giving it a
delegate type and it is not just going
to pick one that would happen to work
(not what side effects that could
have). Line 3 does not work because
we purposely mismatched the method
signature with a delegate having a
different signature (as WaitCallback
takes and object).
Compiles:
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.
In contrast, these work. Line 1 works
because we tell the compiler what
delegate type to use and they match,
so it works. Line 5 works for the
same reason. Note we used the special
form of "delegate" without the parens.
The compiler infers the method
signature from the cast and creates
the anonymous method with the same
signature as the inferred delegate
type. Line 6 works because the
MyMethod() and Action use same
signature.
I hope this helps.
Also see:
http://msdn.microsoft.com/msdnmag/issues/04/05/C20/
What Mark said.
The problem is that Do takes a Delegate parameter. The compiler can't convert the anonymous methods to Delegate, only a "delegate type" i.e. a concrete type derived from Delegate.
If that Do function had took Action<>, Action<,> ... etc. overloads, you wouldn't need the cast.
The problem is not with your delegate definition, it's that the parameter of the Do() method is of type System.Delegate, and the compiler generated delegate type (FakeSave) does not implicitly convert to System.Delegate.
Try adding a cast in front of your anonymous delegate:
Expect.Call(delegate { _dao.Save(t); }).Do((Delegate)delegate { t.Message = "I drink goats blood"; });
Try something like:
Expect.Call(delegate { _dao.Save(t); }).Do(new EventHandler(delegate(Transaction t2) { t2.CheckInInfo.CheckInMessage = "I drink goats blood"; }));
Note the added EventHandler around the delegate.
EDIT: might not work since the function signatures of EventHandler and the delegate are not the same... The solution you added to the bottom of your question may be the only way.
Alternately, you could create a generic delegate type:
public delegate void UnitTestingDelegate<T>(T thing);
So that the delegate is not Transaction specific.