1

I found myself working with a library that defines three clases. The class Element and the class ElementFile : Element which is a child class of the first one, and a third class called Message.

I have been copying some functionalities from an other program that has been given to me as an example on how to use the previously mentioned library. This program is written in VisualBasic but we are currently working with C# so I ended up finding a part of the code I don't know how to adapt.

In VisualBasic they are doing this:

Dim message As Message = library.NewMessage
Dim elem As New ElementFile("path")
message.addElement(elem)

And with my lack of knowledge I tried to reproduce it like this in C#:

Message message = library.NewMessage();
ElementFile elem = new ElementFile("path");
message.addElement(ref elem);

The problem is that the method addElement expects the first parameter to be of Element type. I used JustDecompile to check the declaration of this method in the library and it looks like this:

public class Message
{
    public void addElement(ref Element elem){ ... }
}

Why is addMethod accepting an ElementFile variable as parameter in VisualBasic and how to do the same in C#? Can someone confirm me please if the VisualBasic code makes any sense?

braX
  • 11,506
  • 5
  • 20
  • 33
Grirg
  • 275
  • 3
  • 15

2 Answers2

3

Change the declared type of elem to Element, and the C# code will compile:

Element elem = new ElementFile("path");
message.addElement(ref elem);

And here's why: ref Element e means "e must be a thing to which you may assign an instance of Element". A reference to ElementFile does not meet that requirement.

The method could be doing this:

public void Test(ref Element e)
{
    e = new Element();
}

That's fine if the referenced reference back in the caller is of type Element. It's not at all fine if we were given a ref to a reference of a derived type such as ElementFile. Then we'd be effectively doing this:

ElementFile e = new ElementFile();

//  Nope. 
e = new Element();

If we just add a constraint saying the method can't assign to it, then it's not ref any more: You implement exactly that in your method by omitting the ref keyword.

So the compiler won't let you do that with ref.

This is essentially the same reason why you can't cast IList<ElementFile> to IList<Element>, but you can cast IEnumerable<ElementFile> to IEnumerable<Element>.

As for the reason why the VB code works, see Hans Passant's excellent answer to a very similar question. VB has an explicit special case for this.

  • Thank you for such a well argumented and structured answer with references to similar cases. Very instructive, so much appreciated. – Grirg Dec 13 '17 at 08:17
0

It should work if you do this (note the variable type change for elem):

Message message = library.NewMessage();
Element elem = new ElementFile("path");
message.addElement(ref elem);
itsme86
  • 19,266
  • 4
  • 41
  • 57