locked
The call is ambiguous between the following methods or properties

    Question

  • Code Snippet

        class Class1
        {
            public void F<T>(IEnumerable<T> enumerable, Action<T> action)
            {
                F<T, T>(enumerable, action);
            }
            public void F<TItem, TAction>(IEnumerable<TItem> enumerable, Action<TAction> action) where TItem: TAction
            {
                foreach (TItem item in enumerable)
                    action(item);
            }
            public void Method(int i) {}

            public void Test()
            {
                IList<int> list = new List<int>();
                list.Add(1);
                list.Add(2);
                list.Add(3);

                F(list, Method);                    // .NET 1.1
                F(list, delegate(int i) { });        // .NET 2.0    //Not compile
                F(list, i => { });                    // .NET 3.5
            }
        }


    why code with anonymous delegate don't compile?
    Friday, February 08, 2008 2:31 PM

All replies

  •  Nazar Revutsky wrote:
    Code Snippet

        class Class1
        {
            public void F<T>(IEnumerable<T> enumerable, Action<T> action)
            {
                F<T, T>(enumerable, action);
            }
            public void F<TItem, TAction>(IEnumerable<TItem> enumerable, Action<TAction> action) where TItem: TAction
            {
                foreach (TItem item in enumerable)
                    action(item);
            }
            public void Method(int i) {}

            public void Test()
            {
                IList<int> list = new List<int>();
                list.Add(1);
                list.Add(2);
                list.Add(3);

                F(list, Method);                    // .NET 1.1
                F(list, delegate(int i) { });        // .NET 2.0    //Not compile
                F(list, i => { });                    // .NET 3.5
            }
        }


    why code with anonymous delegate don't compile?

     

    I've never been able to use the anonymous delegate syntax without putting it in the constructor of a delegate type (i.e. saying something like "new Action<int>(delegate(int i) { })".  I'm not sure whether it's supposed to work without it but if it is, I haven't found a place where I could get it to work like that.

    Friday, February 08, 2008 2:36 PM
  • Code Snippet

        class Class1
        {
            public void F<T>(IEnumerable<T> enumerable, Action<T> action)
            {
                F<T, T>(enumerable, action);
            }
            public void F<TItem, TAction>(IEnumerable<TItem> enumerable, Action<TAction> action) where TItem : TAction
            {
                foreach (TItem item in enumerable)
                    action(item);
            }
            public void Method(int i) { }

            public void Test()
            {
                IList<int> list = new List<int>();
                list.Add(1);
                list.Add(2);
                list.Add(3);

                F(list, Method);                    // .NET 1.1
                F(list, delegate(int i) { });        // .NET 2.0    //Not compile
                F(list, new Action<int>(delegate(int i) { }));        // .NET 2.0    //Not compile
                F(list, i => { });                    // .NET 3.5
            }
        }


    F(list, new Action<int>(delegate(int i) { })); // also not compile
    Friday, February 08, 2008 2:47 PM
  •  Nazar Revutsky wrote:
    Code Snippet

        class Class1
        {
            public void F<T>(IEnumerable<T> enumerable, Action<T> action)
            {
                F<T, T>(enumerable, action);
            }
            public void F<TItem, TAction>(IEnumerable<TItem> enumerable, Action<TAction> action) where TItem : TAction
            {
                foreach (TItem item in enumerable)
                    action(item);
            }
            public void Method(int i) { }

            public void Test()
            {
                IList<int> list = new List<int>();
                list.Add(1);
                list.Add(2);
                list.Add(3);

                F(list, Method);                    // .NET 1.1
                F(list, delegate(int i) { });        // .NET 2.0    //Not compile
                F(list, new Action<int>(delegate(int i) { }));        // .NET 2.0    //Not compile
                F(list, i => { });                    // .NET 3.5
            }
        }


    F(list, new Action<int>(delegate(int i) { })); // also not compile

     

    I'm not sure why the first one works.  The second two seem not to because the type resolution is possibly occuring in the wrong order (for your case to work, not necessarily the 'wrong' order for the compiler).

     

    I think it's generally a bad idea to overload generics like this anyway (i.e. provide different lists of generic arguments for functions with the same name), but that's a personal style thing.  For instance, your second call will work to resolve all of the first one's calls, without the extra level of indirection, so why declare both?  Also, if you have different behavior for the two functions, it would be VERY confusing, since most callers wouldn't be sure by looking at the signature which one they'll get without explicitly picking one.  Frankly I'm a bit surprised that any of the code compiles (i.e. the other types of calls), since it is truly an ambiguous call.  By the way, you can pick one by doing:

     

    F<int>(list, delegate(int i) { });

    F<int>(list, new Action<int>(delegate(int i) { }));

     

    Friday, February 08, 2008 3:27 PM
  • This line....

     

    Code Snippet
    F(list,
    delegate(int i) { });

     

     

    ...compiled for me using VS2005 and .NET 2.0.

     

    Rudedog

    Friday, February 08, 2008 3:31 PM
  • Yep, and the line:

    Code Snippet

    F(list, (int i) => { });


    Doesn't compile either. In this instance though I'm not sure which way I could consider to be the bug. The call to F(list, delegate(int i) { }); as well as F(list, (int i) => { }); legitimately do create a situation where both of those methods could be called with those parameters. What I'm not sure about is why the .net 1.1 line *does* compile in this instance. Just because the types match doesn't mean the compiler should just go ahead and pick the first method.

    Tuesday, February 12, 2008 5:03 PM