Anonymous delegates don't seem to enforce type-checking
anonymous-function, c#, delegates
Solution
No, This enforces the type checking. It will take default values if the params are not supplied for anonymous function when assigning to a delegate.
Refer C# language spec(§6.5), it states
An anonymous-method-expression or lambda-expression is classified as an anonymous function (§7.14). The expression does not have a type but can be implicitly converted to a compatible delegate type or expression tree type. Specifically, a delegate type D is compatible with an anonymous function F provided:
- If F contains an anonymous-function-signature, then D and F have the same number of parameters.
- If F does not contain an anonymous-function-signature, then D may have zero or more parameters of any type, as long as no parameter of D has the out parameter modifier.
If you compile Your source code & Open it in Reflector (in framework 1.1 setup), you ll see the compiler automatically assigns default parameters to the Anonymous methods that doesnt have the param list.
del_TestWithNoParams d4_nocompile = (CS$<>9__CachedAnonymousMethodDelegate40 != null) ? CS$<>9__CachedAnonymousMethodDelegate40 : (CS$<>9__CachedAnonymousMethodDelegate40 = new del_TestWithNoParams(Program.<Main>b__27));
del_TestWithThreeInts d5_nocompile = (CS$<>9__CachedAnonymousMethodDelegate41 != null) ? CS$<>9__CachedAnonymousMethodDelegate41 : (CS$<>9__CachedAnonymousMethodDelegate41 = new del_TestWithThreeInts(Program.<Main>b__28));
del_TestWithIntPtr d6_nocompile = (CS$<>9__CachedAnonymousMethodDelegate42 != null) ? CS$<>9__CachedAnonymousMethodDelegate42 : (CS$<>9__CachedAnonymousMethodDelegate42 = new del_TestWithIntPtr(Program.<Main>b__29));
And b__28(method for the delegate del_TestWithThreeInts) will be something like this
[CompilerGenerated]
private static void <Main>b__28(int, int, int)
{
Console.WriteLine("AnonymousDel d5");
}
Problem
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")); ```