I've put together a small code-sample below (Currently in C# 3.5 but would also like to know if the answer is any different in C# 4.0)
I have three simple delegates, and three simple functions ... No problem here, everything compiles as expected, and will not compile if I accidentally try to link delegate A with Method B etc (wrong number of parameters).
What I'm struggling to understand is why the anonymous functions seem happy to be linked to all three of the named delegates
public class Foo
{
public delegate void del_TestWithNoParams();
public delegate void del_TestWithThreeInts(int x, int y, int z);
public delegate void del_TestWithIntPtr(IntPtr ptr);
public void DoStuff()
{
//All OK so Far ... Code will not compile if I mix these up
del_TestWithNoParams d1 =
TestWithNoParams; d1();
del_TestWithThreeInts d2 =
TestWithThreeInts; d2(2, 4, 8);
del_TestWithIntPtr d3 =
TestWithIntPtr; d3(new IntPtr(0x1234567));
//Why do these compile
del_TestWithNoParams d4_nocompile =
delegate { Console.WriteLine("AnonymousDel d4"); };
del_TestWithThreeInts d5_nocompile =
delegate { Console.WriteLine("AnonymousDel d5"); };
del_TestWithIntPtr d6_nocompile =
delegate { Console.WriteLine("AnonymousDel d6"); };
// Edit 1 goes here
}
public void TestWithNoParams()
{ Console.WriteLine("NoParams"); }
public void TestWithThreeInts(int x, int y, int z)
{ Console.WriteLine("Ints: {0},{1},{2}", x, y, z); }
public void TestWithIntPtr(IntPtr ptr)
{ Console.WriteLine("IntPtr: 0x{0:X8}", ptr.ToInt32()); }
}
Also (just to give you a complete runnable app...)
static void Main(string[] args)
{
var f = new Foo();
f.DoStuff();
Console.WriteLine("Done"); Console.ReadLine();
}
Edit 1: Using Lambda Methods
//This work as expected - and fail to build if I get the parameter-count wrong.
del_TestWithNoParams d7 =
(() => Console.WriteLine("Lambda NoParams"));
del_TestWithThreeInts d8 =
((a, b, c) => Console.WriteLine("Lambda Ints: {0},{1},{2}", a, b, c));
del_TestWithIntPtr d9 =
((ptr) => Console.WriteLine("Lambda IntPtr: 0x{0:X8}", ptr.ToInt32()));
Test(d7, d8, d9);
Simple Helper Function:
private void Test(del_TestWithNoParams del_A, del_TestWithThreeInts del_B, del_TestWithIntPtr del_C)
{
del_A();
del_B(2, 4, 8);
del_C(new IntPtr(0x1234567));
}
... Would you agree that this is a better method to write the same code ???
Edit #2 - Summary of Answers
I realise that (whichever way I write the code), the generated IL byte-code is still Type-Safe..
As with many things in C#, named-delegates, anonymous delegates, and lambda methods each have their own place, and there is a balance between "code-readability", "compiler-expansion-of-code" and the suitability for the individual application being written.
The replies below have helped answer the question, and show that the compiler is really doing something similar to the following.
1 - It will NOT allow me to make this mistake
//del_TestWithIntPtr d_mistake_A =
// delegate(int x,int y,int z) { Console.WriteLine(x + y + z); };
2 - The "compiler inferring the types" is expanding the delegate (e.g. d5_nocompile) out to
del_TestWithThreeInts d_clearer_3P =
delegate(int x, int y, int z) { Console.WriteLine(x + y + z); };
3 - It is POSSIBLE to make a mistake (which is still valid code)
del_TestWithThreeInts d_EasyToMakeMistake =
delegate { Console.WriteLine("Oops - forgot to do anything with params"); };
// (this is really :- delegate (int x, int y, int z) {...} )
4 - However, when re-written as a lambda expression, it is slightly more obvious when looking through the code later (or to another developer)
del_TestWithThreeInts d_LessEasyToMakeMistake =
((x, y, z) => Console.WriteLine("Still POSSIBLE to make mistake, but more obvious"));