views:

346

answers:

4

I have a method Foo4 that accepts a parameter of the type Func<>. If I pass a parameter of anonymous type , I get no error. But if I create and pass an object of the type 'delegate' that references to a Method with correct signature, I get compiler error. I am not able to understand why I am getting error in this case.

class Learn6
    {
        delegate string Mydelegate(int a);
        public void Start()
        {
            Mydelegate objMydelegate = new Mydelegate(Foo1);

            //No Error
            Foo4(delegate(int s) { return s.ToString(); });

            //This line gives compiler error.
            Foo4(objMydelegate);

        }

        public string Foo1(int a) { return a.ToString();}



        public void Foo4(Func<int, string> F) { Console.WriteLine(F(42)); }
    }
+4  A: 

Because Func<int, string> and MyDelegate are different declared types. They happen to be compatible with the same set of methods; but there is no implicit conversion between them.

itowlson
Understood what you said, but what happens when I pass delegate(int s) { return s.ToString(); } to Foo4?. Is it getting implicitily converted to Func<> ?
pradeeptp
Essentially, yes. The compiler recognises that the anonymous method is a valid Func<int, string>, and effectively silently converts it to a declaration `string _Anon_Method_(int s) { ... }` and `new Func<int, string>(_Anon_Method_)`. But when you explicitly pass a MyDelegate where a Func<int, string> is expected you defeat that implicit conversion, and get the compiler error.
itowlson
+6  A: 

It works if you pass a reference to the method directly:

Foo4(Foo1);

This is because actual delegates with the same shape are not inherently considered compatible. If the contracts are implicit, the compiler infers the contract and matches them up. If they are explicit (e.g. declared types) no inference is performed - they are simply different types.

It is similar to:

public class Foo
{
    public string Property {get;set;}
}

public class Bar
{
    public string Property {get;set;}
}

We can see the two classes have the same signature and are "compatible", but the compiler sees them as two different types, and nothing more.

Rex M
Thanks. I learned now that it is caused due to type differences, but what happens when an anonymous method is passed to Foo4 as in the original code?
pradeeptp
@pradeeptp since the anonymous method has no type, the type is inferred.
Rex M
Indeed, and personally I think it's a shame they did it like that. Sure there can be benefits to naming parameters and _maybe_ overloading on different delegates with the same "shape", but still. I guess the main reason was the lack of generics support in C# 1, making it impossible to use Action and Func they way they're used now.
Freed
Thanks Rex! :-)
pradeeptp
A: 
        //This line gives compiler error.
        Foo4(objMydelegate);

        //This works ok.
        Foo4(objMydelegate.Invoke);
QrystaL
I didn't know that it could be called like this. Another learning. Thanks! :)
pradeeptp
A: 

depends on the scenario, but in the general case there's no reason to keep around the Mydelegate type, just use Func<int, string> everywhere :)

James Manning