Raisintoe
Raisintoe

Reputation: 201

Can't cast from a child ref to a parent ref in C#. Why not?

I am new to using C#. I am most familiar with C++ and Java when it comes to Object-Oriented Programming and polymorphism. Can someone tell me why this upcast does not work in C#, and what I can do to get the upcast to work with ref.

using System;

public class ParentClass
{
    public int i;
}

public class ChildClass : ParentClass
{
    public char a;
}

public class Program
{
    static void TryMe(ref ParentClass parent)
    {
    
    }
    
    static ChildClass child = new ChildClass();
    
    public static void Main()
    {
        
        TryMe(ref child);
        
        Console.WriteLine("Hello World");
    }
}

Upvotes: 0

Views: 88

Answers (2)

David L
David L

Reputation: 33863

Your issue is caused by your usage of ref, which the C# spec defines as:

A parameter declared with a ref modifier is a reference parameter.

A reference parameter does not create a new storage location. Instead, a reference parameter represents the same storage location as the variable given as the argument in the function member, anonymous function, or local function invocation. Thus, the value of a reference parameter is always the same as the underlying variable.

If the type is modified as part of the call, it can no longer be the same underlying variable.

Passing the reference by value does not have the same restriction:

TryMe(child);
Console.WriteLine("Hello World");


static void TryMe(ParentClass parent)
{

}

static ChildClass child = new ChildClass();

public class ParentClass
{
    public int i;
}

public class ChildClass : ParentClass
{
    public char a;
}

As mentioned in the comments, you either need to remove ref and pass the references by value, or you need to include methods for all polymorphic cases:

TryMe(ref child);
TryMe(ref parent);

static void TryMe(ref ParentClass parent) { }
static void TryMe(ref ChildClass parent) { }

static ChildClass child = new ChildClass();
static ParentClass parent = new ParentClass();

public class ParentClass
{
    public int i;
}

public class ChildClass : ParentClass
{
    public char a;
}

Upvotes: 1

Joe Sewell
Joe Sewell

Reputation: 6620

Your static field child is of type ChildClass. Classes are reference types, so the child property is a reference to an instance of ChildClass. All instances of ChildClass are also instances of ParentClass, but not vice-versa.

When you pass a reference type by reference, in C#'s model you're really passing the child field itself. As in, you may re-assign that field in the callee:

    static void TryMe(ref ParentClass parent)
    {
         parent = new ParentClass();
    }

This is perfectly valid for this individual method - but in our context, it would cause a problem, because when we reassign parent here, we're actually reassigning the child field... and the child field says it must be an instance of ChildClass, which it wouldn't be the case here - it's an instance of ParentClass only.

So, the type system prohibits you from passing a ref to a subtype of the method's parameter's type.

Upvotes: 0

Related Questions