0

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");
    }
}
Raisintoe
  • 201
  • 1
  • 4
  • 11

2 Answers2

1

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;
}
David L
  • 32,885
  • 8
  • 62
  • 93
  • This is just an example. In my real case, I am required to use the ref key-word. Is it impossible to pass the child to parent as ref? – Raisintoe Mar 01 '23 at 22:46
  • Why do you need to use the `ref` keyword when it's already passed by reference? – JohnLBevan Mar 01 '23 at 22:48
  • 2
    "Why do you need to use the ref keyword when it's already passed by reference?" Passing a reference type by value and passing a reference type by reference *are* different. You can reassign the passed-in value in the latter case, and it will be reflected in the caller. – Joe Sewell Mar 01 '23 at 22:50
  • 1
    @Raisintoe, correct, it is impossible. If you have to pass by reference, you either need to update your code to handle all polymorphic cases, or reconsider your use of `ref`. – David L Mar 01 '23 at 22:55
  • No, C# passes by value without the ref key-word. – Raisintoe Mar 01 '23 at 22:56
  • 1
    @JohnLBevan C# passes the reference "by value" as the default, which is a confusing distinction. – David L Mar 01 '23 at 22:58
0

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.

Joe Sewell
  • 6,067
  • 1
  • 21
  • 34