1

Sorry, this is a basic question, which I cannot find an answer to.

I have to write some code in C#, and I need to create a class member variable that is a reference.

In C++ this code would be

public class MyClass
{
     MyClass(int& m_var): mVar(m_var){}
     int& mVar;
}

However I cannot seem to do this in C#

I can create a constructor with a reference parameter using

MyClass(ref int m_var)

But I cannot create a reference member variable using

class MyClass
{
     MyClass(ref int m_var)
     {
          mVar = m_var;
     }
     ref int mVar;
}

Because the line:

     ref int mVar;

Gives me the error: 'Invalid Token 'ref' in class, struct, or interface member declaration.

Why is this? Why did C# take away the functionality to create reference member variables?

Ðаn
  • 10,934
  • 11
  • 59
  • 95
Mich
  • 3,188
  • 4
  • 37
  • 85
  • 1
    What Ðаn said. Take a look at [this answer](https://stackoverflow.com/a/6253595/5617186) for a question similar to this – Rafael May 31 '17 at 17:43
  • @Ðаn Not if it's an `int`. `int` is a value type. In C#7 you can have `ref` returns and locals, but still not fields. The way to do this is to write a simple class with an `int` property, and share a reference to an instance of that. – 15ee8f99-57ff-4f92-890c-b56153 May 31 '17 at 17:49
  • int is just a placeholder for another class here, I didn't want to complicate it with templates. So what you are saying is that `int mVar` automatically becomes a reference member variable if I assign another reference to it? – Mich May 31 '17 at 17:57
  • 2
    The feature wasn't taken away. It's still there. You just have to declare your intent to shoot yourself in your foot through the use of `unsafe` code. Then you can use pointers just like in C++ (keeping in mind that C++'s `&` reference type is just a pointer in disguise). C# 7 adds `ref` local variables, but it has strict rules to ensure runtime safety, including that such variables must be locals, allowing the compiler to analyze its usage for safety (i.e. make sure the variable doesn't outlive the thing it refers to). – Peter Duniho May 31 '17 at 19:27

1 Answers1

3

int is just a placeholder for another class here

Whoa there! int is not just "another class". int is a value type. You can't have a field that's a reference to it. You can have a ref parameter. In C#7 you can have ref returns and locals, but still not fields.

In the CLR, int is critically different from classes in exactly the area we're talking about here. x is an int on what we'll figuratively call "the stack", since I don't feel like looking up how they actually implemented it. In C, I seem to recall describing that as a stack variable:

int x = 0;

List<T> is a class. y, here, is a "stack variable" which is a rebindable reference to an object on the "heap":

var y = new List<int>();

If you're talking about sharing references to reference types -- any class -- in C# that's easy: It's always a reference.

public class C {
    //  x is passed by value. It is the value of a reference. Seriously, it is. 
    public C(List<String> x) {
        List = x;
    }
    public List<String> List { get; set; }
}

...

var list = new List<String>();
var x = new C(list);
var y = new C(list);

x.List and y.List are the same object, at least until you assign a new object to one of them -- C# references, unlike C++ references (at least as of C++98; I haven't kept up since 2006) are "rebindable".

The way to do this is to write a simple class with an int property, and share a reference to an instance of that. where T : struct restricts T to be a struct rather than a class. In CLR-land, that means "value type" rather than "reference type".

public class Reference<T> where T : struct
{
    public Reference(T t) {
        Value = t;
    }

    public T Value { get; set; }
}

class MyClass
{
     MyClass(Reference<int> ref)
     {
          _ref = ref;
     }
     Reference<int> _ref;
}

Why did C# take away the functionality to create reference member variables?

They didn't "take it away"; they didn't abduct an infant C++ compiler and cut its toes off. They just didn't think it was a good idea to do that in C#, and they were right. C# isn't C and it isn't meant to be C. Dennis Ritchie designed C to be used by people like Ken Thompson; Anders Hejlsberg explicitly designed C# to be used by the rest of us, who are much more easily confused.

This is built deeply into .NET:

The CLR type system however does not allow for fields that are aliases to other variables

(That's an old essay; C#7 now does support the additional uses of ref that the CLR supported all along).

New C# programmers already have more than enough trouble with ref and reference types. Just recently I saw code in a question here much like this:

public void F(ref List<int> x) { ... }

The fellow who wrote that code just wanted to pass in a List<int> without creating an expensive copy of it.