Anonymous delegates don't seem to apply type checking

I put together a small code example below (currently in C # 3.5, but also would like to know if the answer is 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 associate delegate A with method B, etc. (wrong number of parameters).

What I'm trying to understand is why anonymous functions seem happy for all three of these 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 executable application ...)

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

... Do you agree that this method is better for writing the same code ???


Edit # 2 - Summary of Responses

I understand that (no matter how I write the code), the generated IL bytecode is still type-safe.

As in many cases in C #, named-delegates, anonymous delegates and lambda methods have their own place, and there is a balance between "readability of the code", "compiler-extension-code" and the suitability of writing a separate application.

The answers below helped answer the question and showed that the compiler really does something similar to the following.

1 - This 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 - "Type Compiler" expands the delegate (e.g. d5_nocompile) to

 del_TestWithThreeInts d_clearer_3P = delegate(int x, int y, int z) { Console.WriteLine(x + y + z); }; 

3 - POSSIBLE to make a mistake (which is still a 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-writing as a lambda expression, this is a little more obvious when viewing the code later (or to another developer)

 del_TestWithThreeInts d_LessEasyToMakeMistake = ((x, y, z) => Console.WriteLine("Still POSSIBLE to make mistake, but more obvious")); 
+4
source share
3 answers

No, this forces type checking. It will take default values ​​if parameters are not provided for an anonymous function when assigned to a delegate.

Note the C # language specification (Β§6.5), it states

An anonymous method expression or lambda expression is classified as an anonymous function (Β§7.14). the expression has no type, but can be implicitly converted to a compatible delegate type or expression tree type. In particular, a delegate of type D is compatible with the anonymous function F provided that:

  • If F contains the signature of an anonymous function, then D and F have the same number of parameters.
  • If F does not contain the signature of an anonymous function, then D can have zero or more parameters of any type, if no parameter D has an output parameter modifier.

If you compile the source code and open it in Reflector (in setting 1.1), you will see that the compiler automatically assigns default parameters to anonymous methods that do not have a list of parameters.

  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 (the 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"); } 
+3
source

When anonymous methods are used, what really happens is that the class is created with the property defined for each of the delegate options.

If you do not pass parameter values, the default values ​​are used.

+1
source

If you do not specify parameters for anonymous methods created using the delegate keyword, the parameters will be automatically output by the compiler, so it does not matter what the delegate signature is

0
source

Source: https://habr.com/ru/post/1302091/


All Articles