locked
Method overloading from a generic method. RRS feed

  • Question

  • I have a static function with overloads:

    public static void Foo(object obj) { ... }
    public static void Foo(bool b) { ... }

    And I have a generic class and method, in which I call the static function.

    class Class<A, B>
    {
        public void Func(A a, B b)
        {
            Foo(a);
            Foo(b);
        }
    }

    If I run the following code:

    Class<string, bool> inst = new Class<string, bool>();
    string str = null;
    bool b = false;
    inst.Func(str, b);

    The "Foo(bool)" function never gets called.  Only the "Foo(object)" version is called (twice), even though the compiler knows parameter "b" is of type bool, it still invokes the overload for the generic "object" version.

    If I add a "void Foo<T>(T obj)" to the mix, that version is always called, and never the other specific overloads.

    When calls to the various overloads are made outside of the scope of the generic Class, everything works as just as expected.

    I know what I want can be done if I combine the various "void Foo()" implementations into a single version that takes "object", and use run-time type checking to do the appropriate action.  However, I want this to be done instead at compile time, and haven't been able to figure out why it doesn't work, or how to trick the compiler into doing what I want it to.


    Saturday, August 25, 2007 4:41 AM

Answers

  • Hi Adam

    The problem is "bool" is also "object". Such syntax is amphibolous.

    When the compiler find the *right* overload of method void Foo(object obj) it doesn't continue to seach and compare the next one.

     

    Thanks

    Monday, August 27, 2007 7:40 AM
  • I believe that it searches linerally in order, i think. So one thing you could try is swapping the definitions:

    public static void Foo(bool b) { ... }

    public static void Foo(object obj) { ... }

    instead of

    public static void Foo(object obj) { ... }
    public static void Foo(bool b) { ... }

    It may be an issue of redesigning the class, as object is the perfect overload for everything. Any reason why you're doing object? I notice that you don't bother to handle the sting overload and just let it use the object overload in this example.
    Monday, August 27, 2007 3:24 PM
  • Generic method bodies are compiled without knowledge of the actual types to which type variables will be bound. The compiler can only use information from constraints on the type variables. The body of Func() is compiled in such a way that it works with any type arguments. That means in this case that the compiler must choose a Foo method to call that will work with any type. This is in contrast to C++ templates which are more like code generators.

    Monday, August 27, 2007 6:15 PM

All replies

  • Here's a more elaborate illustration of the problem:

    Code Snippet

    namespace ConsoleApplication1
    {
        class Program
        {
            public static void Foo(object obj) { }

            public static void Foo(bool b) { }

            public static void Foo<T>(T obj) { }

            public class Class<T>
            {
                T var;

                public Class(T var) { this.var = var; }

                public void Func() { Foo(var); }

                public void Bar()
                {
                    System.Reflection.MethodInfo method = typeof(Program).GetMethod("Foo", new System.Type[] { typeof(T) });

                    method.Invoke(null, new object[] { var });
                }
            }

            static void Main(string[] args)
            {
                Foo("");    //correctly calls Foo<T>(T)
                Foo(null);  //correctly calls Foo(object)
                Foo(true);  //correctly calls Foo(bool)

                (new Class<string>("")).Func();    //correctly calls Foo<T>(T)
                (new Class<object>(null)).Func();  //incorrectly calls Foo<T>(T)
                (new Class<bool>(true)).Func();    //incorrectly calls Foo<T>(T)

                (new Class<string>("")).Bar();    //inconveniently calls Foo(object)
                (new Class<object>(null)).Bar();  //correctly calls Foo(object)
                (new Class<bool>(true)).Bar();    //correctly calls Foo(bool)
            }
        }
    }



    Saturday, August 25, 2007 7:09 AM
  • Hi Adam

    The problem is "bool" is also "object". Such syntax is amphibolous.

    When the compiler find the *right* overload of method void Foo(object obj) it doesn't continue to seach and compare the next one.

     

    Thanks

    Monday, August 27, 2007 7:40 AM
  • I believe that it searches linerally in order, i think. So one thing you could try is swapping the definitions:

    public static void Foo(bool b) { ... }

    public static void Foo(object obj) { ... }

    instead of

    public static void Foo(object obj) { ... }
    public static void Foo(bool b) { ... }

    It may be an issue of redesigning the class, as object is the perfect overload for everything. Any reason why you're doing object? I notice that you don't bother to handle the sting overload and just let it use the object overload in this example.
    Monday, August 27, 2007 3:24 PM
  • Generic method bodies are compiled without knowledge of the actual types to which type variables will be bound. The compiler can only use information from constraints on the type variables. The body of Func() is compiled in such a way that it works with any type arguments. That means in this case that the compiler must choose a Foo method to call that will work with any type. This is in contrast to C++ templates which are more like code generators.

    Monday, August 27, 2007 6:15 PM