5

When the formal argument of a method is of type 'object' it is possible, through inheritance, for the actual argument to be any object type. Once in the method the object can be cast to the type expected. All's fine.

If, however, the signature of the method has a formal argument of 'object', using the ref keyword i.e. methodname(ref object), the compiler throws an error stating that:

"The best overloaded method match for 'ByRefTest.Program.changeMeByRef(ref object)' has some invalid arguments. "Argument '1': cannot convert from 'ref ByRefTest.Person' to 'ref object'"

The difference between using or not using the ref keword when passing objects as parameters is explained very well in A. Friedman's blog http://crazorsharp.blogspot.com/2009/07/passing-objects-using-ref-keywordwait.html , but why is it not possible to pass a custom type as an actual argument when the formal argument of type 'object' uses the ref keyword?

As an example:

class Program
{
    static void Main(string[] args)
    {
        Person p = new Person();

        changeMe(p); // compiles
        changeMeByRef(ref p); // throws error

        object pObject = (object)p;
        changeMeByRef(ref pObject); // compiles
    }


    public static void changeMeByRef(ref object obj)
    {
        Person p = (Person)obj;
    }

    public static void changeMe(object obj)
    {
        Person p = (Person)obj;

    }
}

public class Person
{
}

Thanks.

ps I just changed the signature to:

public static void changeMeByRef<T>(ref T obj) where T : Person

this compiles for changeMeByRef(ref p);

iWeasel
  • 446
  • 1
  • 5
  • 12
  • This is a duplicate of http://stackoverflow.com/questions/1207144/c-why-doesnt-ref-and-out-support-polymorphism/1207302#1207302 – Eric Lippert Sep 30 '09 at 14:54

4 Answers4

8

Because the method might change the parameter to have a value of different type, in violation of the type of the variable used for the argument. Simple example:

public void Foo(ref object x)
{
    x = "hello";
}

...

// This doesn't compile, fortunately.
Stream y = null;
Foo(ref y);

What's the value of y after the assignment in the method? It should be a string - but that violates the type of the variable. That would be a Very Bad Thing, completely violating type safety. This is the same kind of reason for the generic invariance of IList<T> even in .NET 4.0.

Eric Lippert recently blogged about the invariance of ref in more detail.

LBushkin
  • 129,300
  • 32
  • 216
  • 265
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
2

Because the ref parameter work both ways. You can assign the parameter to an arbitrary object inside your function, and the calling code needs to handle it.

Grzenio
  • 35,875
  • 47
  • 158
  • 240
1

Eric Lippert explains in Why do ref and out parameters not allow type variation?

Dzmitry Huba
  • 4,493
  • 20
  • 19
0

do this. it is easier.
changeMe(p); // compiles
changeMeByRef(ref (Object)p); // this time it should not throw errors.

Behrooz
  • 1,696
  • 2
  • 32
  • 54