none
Object class, value type and reference type. RRS feed

  • Question

  • Hi,

    The query is quite basic but the more I read on this topic, getting more confused.

    The program below calls the function 2 - seems this is because null is (generally) related to reference types, so the call       a(null); resolves to the function 2 which accepts string (a reference type) as an argument.

     static void Main(string[] args)
            {
                a(null);
            }

    /*Function 1*/

            static int a(int a)
            { return 1; }

    /*Function 2*/

            static int a(string a)
            { return 1; }

    Now in the program below it again resolves to the same function 2, but here function 1 accepts object argument which is a reference type (or not?). Then why it reolves to function 2 and not function 1 this time.

    static void Main(string[] args)
            {
                a(null);
            }

    /*Function 1*/

            static int a(object a)
            { return 1; }

    /*Function 2*/

            static int a(string a)
            { return 1; }

    Any pointers would be appreciated.

    Sunday, August 12, 2012 6:39 PM

Answers

  • To paraphrase the question you ask in your last paragraph:

    The compiler chooses function 2 instead of function 1. Is this because string is derived from object?

    Yes. Think about it like this. Suppose instead you had

    abstract class Animal {}
    abstract class Mammal : Animal {}
    abstract class Tiger : Mammal {}
    ...
    void M(Mammal m){}
    void M(Animal a){}
    ...
    M(new Tiger());

    You would expect that the Mammal version, not the Animal version, would be called, right? The compiler knows that Mammal is the better choice because every Mammal is convertible to Animal, but not every Animal is convertible to Mammal. Therefore Mammal is more specific.

    By the same logic, the string version is better than the object version. Every string is an object, not every object is a string, so string is more specific and therefore is the better choice.

    This can get quite confusing. For example, many people are confused by this code:

    void N(params object[] p) {}
    void N(object o) {}
    ...
    N(null);

    What happens? There are three possibilities. This code could be treated like:

    N((object[]) null); // 1
    N(new object[] { null } ); // 2
    N((object)null); // 3

    Take a guess as to which one is right.

    .

    .

    .

    .

    .

    Option 1 is correct. You know that option 3 cannot be chosen because again, every object[] is an object, but not every object is an object[], so object[] is more specific, so version 3 loses. Option 2 loses because a method that is applicable in its expanded form is worse than a method applicable in its normal form. And that leaves option 1 as the winner.

    For the exact rules, read section 7.5.3.2 of the C# 4 specification.



    Thursday, August 16, 2012 9:20 PM

All replies

  • I modified the code below and now it is calling function 1.  Your code has two functions named "a".  when you have more than one function with the same name Visual Studio attempts executes the function that matches the parameter types of the statement which is calling the function.  Visual Studio considers "null" to be a better match to a string than an object.  I create a variable b which is an object and now it calls function 1.

            static void Main(string[] args)
            {
                object b = null;
                a(b);
            }

            /*Function 1*/

            static int a(object a)
            { return 1; }

            /*Function 2*/

            static int a(string a)
            { return 1; }

    Here I type cast null to be an object and get the same results

            static void Main(string[] args)
            {
                a((object)null);
            }

            /*Function 1*/

            static int a(object a)
            { return 1; }

            /*Function 2*/

            static int a(string a)
            { return 1; }


    jdweng

    Sunday, August 12, 2012 9:53 PM
  • Hi Joel,

    Thanks for your reply. actually I just wanted to know the same. Why the compiler resolves the call to the function 2 in the original code, though both are the reference types.

    e.g if there is one more function a(SomeClass a) then compiler will throw error, which is quite understandable for me.

    So in case of parameter as object, what is the reason that the compiler chooses the function 2 instead of function 1. Is this because string is "more" concrete implementation of object. Or is there something like the object is not a reference type at all in the undelying impllementation.

    Monday, August 13, 2012 4:28 PM
  • To paraphrase the question you ask in your last paragraph:

    The compiler chooses function 2 instead of function 1. Is this because string is derived from object?

    Yes. Think about it like this. Suppose instead you had

    abstract class Animal {}
    abstract class Mammal : Animal {}
    abstract class Tiger : Mammal {}
    ...
    void M(Mammal m){}
    void M(Animal a){}
    ...
    M(new Tiger());

    You would expect that the Mammal version, not the Animal version, would be called, right? The compiler knows that Mammal is the better choice because every Mammal is convertible to Animal, but not every Animal is convertible to Mammal. Therefore Mammal is more specific.

    By the same logic, the string version is better than the object version. Every string is an object, not every object is a string, so string is more specific and therefore is the better choice.

    This can get quite confusing. For example, many people are confused by this code:

    void N(params object[] p) {}
    void N(object o) {}
    ...
    N(null);

    What happens? There are three possibilities. This code could be treated like:

    N((object[]) null); // 1
    N(new object[] { null } ); // 2
    N((object)null); // 3

    Take a guess as to which one is right.

    .

    .

    .

    .

    .

    Option 1 is correct. You know that option 3 cannot be chosen because again, every object[] is an object, but not every object is an object[], so object[] is more specific, so version 3 loses. Option 2 loses because a method that is applicable in its expanded form is worse than a method applicable in its normal form. And that leaves option 1 as the winner.

    For the exact rules, read section 7.5.3.2 of the C# 4 specification.



    Thursday, August 16, 2012 9:20 PM