Why is it not referencing the work of a derived class for a method requiring a base class reference?

I get a compiler error below. I don’t know why I cannot take a reference to a derived class and pass it to a method that accepts a reference to the base class. Note that the foo () and bar () methods do not necessarily have the same semantics, so they must have different names, these methods are not a problem.

public class X { public int _x; } public class Y : X { public int _y; } public class A { public void foo( ref X x ) { x._x = 1; } } public class B : A { public void bar( ref Y y ) { foo( ref y ); // generates compiler error foo( ref (X)y); // wont work either y._y = 2; } } 

The only solution I found was:

 public class B : A { public void bar( ref Y y ) { X x = y; foo( ref x ); // works y._y = 2; } } 

I know that "y" is never initialized in bar (), but since its declared as ref itself must be initialized outside the method, so the problem cannot be the problem. Any coverage that you can shed on this question would be helpful. I am sure that this is just my understanding of C #, which is not enough, it will work in C ++ with the cast.

+7
c #
source share
6 answers

Since there is no way to guarantee that you will not replace the link with an instance of a type that is completely different from what you passed in the first place.

Given:

 class Base {} class Hamster : Base {} class ADentist : Base {} void ohWait(ref Base obj) { obj = new ADentist(); } 

When calling this method:

 var foo = new Hamster(); ohWait(ref foo); 

would break terribly. Eric Lippert explains this better than me: Why don't the ref and out parameters allow me to change the type?

+14
source share

A simple example to illustrate why this is unacceptable (using the X and Y classes from your example)

 void ReplaceX(ref X x) { x = new X(); } void Test() { X x = new X(); ReplaceX(ref x); // Fine, our local variable x is now replaced Y y = new Y(); ReplaceX(ref y); // Error, since it would replace our local // variable typed as Y with an instance of X } 
+2
source share

When you give a function that requires ref X a ref Y , instead you say: "Here I have X for you, you can change the link to point to a new object."

While each derived class can be used instead of its own superclass, the same does not work differently.

The method can simply indicate your ref Y , which you passed to an instance of X that is not Y This may not work. At least not with a system like C #.

+1
source share

Suppose foo really did this:

 x = new X(); 

Then your y variable in B.bar() will no longer refer to an instance of Y that would be Bad Thing.

For more on this, see Eric Lippert's blog post .

I agree with the other posters - you do not need to use ref . See the article on passing parameters for more information on this topic.

+1
source share
0
source share

I know this is a very old question, but, seeing that I am trying to find a solution to this problem and cannot, I decide to publish a quick workaround for any people who decide to visit this issue in the future. The best way to get around a C # type system is to use templates / generic types to your advantage:

 public class A { public void foo<T>( ref T x ) where T : X { x._x = 1; } } public class B : A { public void bar( ref Y y ) { foo<Y>( ref y ); // works now y._y = 2; } } 

The foo function now extends to all subclasses of type X, but you must make sure that you specify the correct generic type.

0
source share

All Articles