15

I know complex types are passed by Reference in C# and primitive types are passed by Value. Can I pass primitive types by reference in C#?

Update:

Thanks for answers, but my example is?

void test(object x) {

}

long y = 1;

test(ref y);

This throw this exception: The 'ref' argument type doesn´t match parameter type

Acaz Souza
  • 8,311
  • 11
  • 54
  • 97
  • 7
    primitive and complex are not the correct terms here. You are talking about Value-Types and Reference-Types. – H H Aug 19 '11 at 13:23
  • 1
    you need to have `void test (ref object x)`, as `ref` needs to be used both in the method definition and its usage – Alex Aug 19 '11 at 13:41
  • "Complex Types" are not passed by reference. All types are passed by value unless you use the ref or out keywords. – Chris Dunaway Aug 19 '11 at 14:00
  • 1
    You need `ref` in both the function definition and the call to the function. – Daniel Aug 19 '11 at 14:11
  • possible duplicate of [C# : Why doesn't 'ref' and 'out' support polymorphism?](http://stackoverflow.com/questions/1207144/c-why-doesnt-ref-and-out-support-polymorphism) – Eric Lippert Aug 19 '11 at 15:02

6 Answers6

22

There are a couple of different questions here.

Can I pass primitive types by reference in C#?

First off, let's make sure that the jargon is correct here. It is unclear what you mean by a "primitive type". Do you mean a "built into the runtime" type like int or long? Do you mean any value type whether it is built-in or user-defined?

I'm going to assume that your question actually is

Can I pass value types by reference in C#?

Value types are called value types because they are passed by value. Reference types are called reference types because they are passed by reference. So it would seem that the answer is by definition, no.

However, it's not quite so straightforward as that.

First, you can turn an instance of value type into an instance of reference type by boxing it:

decimal d = 123.4m; // 128 bit immutable decimal structure
object o1 = d; // 32/64 bit reference to 128 bit decimal
object o2 = o1; // refers to the same decimal
M(o2); // passes a reference to the decimal.
o2 = 456.78m; // does NOT change d or o1

Second, you can turn an instance of value type into a reference by making an array:

decimal[] ds1 = new decimal[1] { 123.4m }; 
decimal[] ds2 = ds1;
ds2[0] = 456.7m; // does change ds1[0]; ds1 and ds2 refer to the same array

Third, you can pass a reference to a variable (not a value -- a variable) using the "ref" keyword:

decimal d = 123.4m;
M(ref d);
...
void M(ref decimal x)
{ // x and d refer to the same variable now; a change to one changes the other

Attempting to pass a ref long to a method that takes a ref object causes a compilation error: The 'ref' argument type doesn´t match parameter type

Correct. The type of the variables on both sides must match exactly. See this question for details:

Why doesn't 'ref' and 'out' support polymorphism?

Community
  • 1
  • 1
Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
16

Sure you can:

public void MyFunction(ref int a)
{
}
Seva Alekseyev
  • 59,826
  • 25
  • 160
  • 281
  • Also see the doc at http://msdn.microsoft.com/en-us/library/14akc2c7(v=vs.71).aspx as the ref method has a few gotchas with respect to initialization and overloading – Lars Tackmann Aug 19 '11 at 13:21
10

Just use the ref or out parameter modifier.

void myMethod(ref int myValue) ...

ref is 2 way. out is 1 way.

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
9

You can using the ref word next to the parameter in the function definition.

public void func(ref int a)
{
    //do stuff
}

public void doStuf()
{
    int a = 5;
    func(ref a);
}
Daniel
  • 6,595
  • 9
  • 38
  • 70
2

You're mixing concepts. The default parameter passing convention is by value. You can pass a reference type object to a method or pass a value type object to the method. You pass the object by using a variable. That variable is passed by value. Inside the method, the parameter is a copy of the variable you passed.

If you decorate the parameter with ref or out, then mutating what you have inside the method will also affect the passed variable.

// Doesn't change obj1
void DoesntChange(object obj)
{
    obj = new object(); // Assigns a new object to the local variable obj.
}

var obj1 = new object();
DoesntChange(obj1);

// Will change obj2
void WillChange(ref object obj)
{
    obj = new object(); // Assigns a new object to the local ref variable obj
                        // and changes the obj2 variable to point at the new object.
}

var obj2 = new object();
WillChange(ref obj2);

To mutate a primitive type variable parameter inside a method and persist the change at the call site, it must be passed by ref or out.

Johann Gerell
  • 24,991
  • 10
  • 72
  • 122
1

Post-update you can pass boxed values around by reference.

static void Main(string[] args)
{
    var value = 10;
    var boxed = (object)value;
    TakesValueByRef(ref boxed);
    value = (int)boxed;
    // value now contains 5.
}

static void TakesValueByRef(ref object value)
{
    value = 5;
}

Just keep in mind it's terrible practice, and risky (due to cast exceptions) to do this.

Jonathan Dickinson
  • 9,050
  • 1
  • 37
  • 60
  • This example does not match the comment above it. You are passing by ref because you used the 'ref' keyword. It has nothing to do with boxing. You can box it by converting to object or by just using the ref keyword, you don't need to do both. – justin.m.chase Aug 19 '11 at 19:21
  • @justin.m.chase try your theories first in the IDE. If you look at his question he wants an object parameter; which involves boxing, which means you need a boxed value before you pass it to the function. – Jonathan Dickinson Aug 20 '11 at 10:10
  • @johnathan: well his question has a number of errors in the code and in terminology. For starters, his code doesn't even compile. And to be honest I don't even understand your response. You don't need boxing to pass value types by reference. It's that simple. Try "void test(ref long value) { value = 5; }" and you'll see that. – justin.m.chase Aug 20 '11 at 22:18
  • @justin.m.chase you need to box it if the method wants an object parameter. – Jonathan Dickinson Aug 21 '11 at 11:26
  • 1
    @justin.m.chase I find it hilarious that you would criticise an answer that you clearly state you don't understand. You made my day with this. – Engineer Feb 23 '12 at 18:05