22

In C++, passing const references is a common practice - for instance :

#include <iostream>
using namespace std;

class X
{
  public :
    X()                              {m_x = 0; }
    X(const int & x)                 {m_x = x; }
    X(const X & other)               { *this = other; }
    X & operator = (const X & other) { m_x = other.m_x; return *this; }
    void print()                     { cout << m_x << endl; }
  private :
    int m_x;
};

void main()
{
    X x1(5);
    X x2(4);
    X x3(x2);
    x2 = x1;
    x1.print();
    x2.print();
    x3.print();
}

This very simple example illustrates how it's done - pretty much. However I've noticed that in C# this doesn't seem to be the case. Do I have to pass const references in C# ? what do I need the "ref" keyword for? Please note that I know and understand what C# reference and value types are.

Jon Seigel
  • 12,251
  • 8
  • 58
  • 92
Maciek
  • 19,435
  • 18
  • 63
  • 87
  • 3
    Since you are thinking in C++ terms probably the best way to think of the ref keyword is as a pointer. If you use it with a value type then it is a single pointer, with a ref type it is a pointer to a pointer. – Martin Harris Sep 06 '09 at 09:01
  • Duplicate: http://stackoverflow.com/questions/114149 – Peter Mortensen Sep 06 '09 at 09:34
  • A good reference for this sort of thing is Eric Lipperts blog. In particular his "References are Not Addresses" entry. http://blogs.msdn.com/ericlippert/archive/2009/02/17/references-are-not-addresses.aspx – Robert Paulson Sep 06 '09 at 09:59
  • @MartinHarris I've read [Jon Skeet](https://stackoverflow.com/users/22656/jon-skeet)['s blog post on the matter](http://www.yoda.arachsys.com/csharp/parameters.html) and couldn't find anything against your comment. Thank you for pointing out the similarity. I believe I've learned the concepts in both c++ and c# better thanks to this very comment. – Nae Mar 20 '18 at 12:52

4 Answers4

27

To answer the ref part of your question; when you pass a variable to a method, a copy of that variable is created. Using the ref keyword will pass the same instance of that variable so the method would be able to update that variable for the caller.

A lot of people seem to think this only applies to value types because reference types are just passed as a reference anyway so the ref keyword has no effect. However, this isn't true, the reference gets passed to the method in the same way as a value; it's copied and a new instance of the that reference is created. This means that the caller will see modifications to the object itself, but not to the reference. So, if you tried to set the object to null, or a new object, the caller would not see this modification if the ref keyword isn't used:

Without ref:

void UpdatePerson(Person person)
{
   // Caller would see this change
   person.Name = "Bob";
   // Caller wouldn't see this change
   person = null;
}

With ref

void UpdatePerson(ref Person person)
{
   // Caller would see this change
   person.Name = "Bob";
   // Caller would see this change
   person = null;
}
Charlie
  • 10,227
  • 10
  • 51
  • 92
  • 1
    Coming from C++, the first example **Without Ref** is very strange! So the `Person` object passed as an argument is copied to a local `Person` object inside `UpdatePerson(Person)` and modifications to the argument's field members are permitted as if the argument was passed by reference, but modifications to the local object does not affect the argument object at all? – Minh Tran Oct 16 '17 at 04:49
  • 1
    @MinhTran Why is it strange in C++? `person` is passed by value, so it totally depends on how copy constructor is defined. For exampe, if member variable `name` is of `std::string` type, the compiler generated copy constructor will behave exactly like C# here. – MaxPlankton Apr 09 '18 at 07:32
22

C# doesn't have the notion of const objects (i.e. objects which you can't modify); only variables (i.e. fields) can be const or readonly - meaning that you cannot assign to them.

The ref keyword conceptually passes a reference to a variable as the parameter, i.e. the callee can modify the variable (rather than just modifying the value). This is particularly useful for the primitive types (int, bool, etc).

Martin v. Löwis
  • 124,830
  • 17
  • 198
  • 235
  • 2
    Actually, int isn't immutable in strict sense, as it can be modified after creation (whereas immutable object can't be changed after it is created). The problem with int and other primitive type is that they are passed by value, so you actually can change them in function, but you will alter their copy, not themselves. So I would rather write "immutable types and primitive types". – Marcin Deptuła Sep 06 '09 at 09:03
  • 1
    Ok, I dropped the mentioning of immutable. – Martin v. Löwis Sep 06 '09 at 11:26
  • 2
    How would you modify an int? Assignment doesn't count (you could also 'modify' immutable reference types by assigning a new reference). int is both a value type and immutable. Indeed, for immutable types, you cannot really tell the difference between reference and value types (except by using ReferenceEquals). Only if a type is mutable (has property setters or mutating methods), the difference between reference and value begins to play a role. Most value types in .NET are immutable (all primitive types, DateTime, TimeSpan, etc.) – Daniel Sep 06 '09 at 17:40
18

Since C# 7.2, this is possible using the in keyword.

Frederik Gheysels
  • 56,135
  • 11
  • 101
  • 154
  • Good option. Thank you. – stephanmg Apr 28 '19 at 21:46
  • 1
    This is ambiguous. It appears "in" works in the way you would expect (coming from C++) if the variable is a POD type (int, float, bool, double, etc), however if the variable is a structure/class/object it only applies the constant to the object reference, and not any of the underlying data... – GarThor Oct 12 '22 at 22:51
8

const correctness in C#

A question of const

Why doesn't C# have "const"?

Community
  • 1
  • 1
KV Prajapati
  • 93,659
  • 19
  • 148
  • 186