22

So I have this mock extension method which change a value to another value:

public static void ChangeValue(this int value, int valueToChange)
{
    value = valueToChange;
}

When I try using it:

int asd = 8;
asd.ChangeValue(10);
Debug.Log(asd);

It returns 8 instead of 10. While the value did change inside the ChangeValue method, it didn't change the value of "asd". What do I need to add to the method, to make it update "asd"?

user1979550
  • 337
  • 1
  • 2
  • 4
  • BTW, what's wrong with direct assigning? `asd = SomeFunctionThatCalculatesAsd();`? – Leri Jan 15 '13 at 08:04
  • 1
    Nothing wrong, just curious about whether or not I can change the value, without using a method that returns a value. – user1979550 Jan 15 '13 at 08:08

6 Answers6

13

You can't do that without using either a return value, or a ref parameter. The latter doesn't work alongside this (extension methods), so your best bet is a return value (rather than void).

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • I see. I just wanted to know if there's any way I don't have to use 'return'. Thanks~! – user1979550 Jan 15 '13 at 08:04
  • @MarcGravell Sorry to bother but I tried the same sample in the user1979550 question with string and nothing changed. So if string is reference type why wouldn't it change? Is there a distinction of reference type passed by reference pointer and reference type passed by value? – yigitt Dec 15 '16 at 13:59
  • 2
    @UfukSURMEN passing a reference type is irrelevant unless the type is mutable. If you had passed in a `User` instance and changed `user.Name = "New Name";`, then the `.Name` would be observed to be changed, but the reference didn't change. Changes to the reference itself (`user = new User("Fred")`) won't be noticed unless the reference is passed by `ref`. Now, `string` is like `user` in this example, but `string` is immutable, so the only way to observe changes is to use `ref` – Marc Gravell Dec 15 '16 at 14:25
11

The old answer is not valid anymore since newer C# versions support this ref. For further details refer to this answer.

Old Answer:

int is a struct so it's a value-type. this means that they are passed by value not by reference. Classes are reference-types and they act differently they are passed by reference.

Your option is to create static method like this:

public static void ChangeValue(ref int value, int valueToChange)
{
    value = valueToChange;
}

and use it:

int a = 10;
ChangeValue(ref a, 15);
Leri
  • 12,367
  • 7
  • 43
  • 60
  • 4
    strictly speaking, classes are typically passed "a reference-value, passed by-value" - it is still by-value. A `ref SomeType` would be "a reference-value, passed by-reference". – Marc Gravell Jan 15 '13 at 07:56
  • @MarcGravell I would argue that by your terminology (which isn't wrong), a `ref int` argument is *also* a reference-value passed by value. It's treated as an argument of type "reference to int", is it not? –  Jan 15 '13 at 08:00
  • @hvd heh; maybe... but in terms of how the terms are applied in the spec re the `ref` modifier; `SomeType foo` is by-value; `ref SomeType foo` is by-reference. – Marc Gravell Jan 15 '13 at 08:02
  • Ah yes, I was looking at it from an IL perspective, but the C# rules are more relevant here. –  Jan 15 '13 at 08:08
  • @MarcGravell You are right I should be more accurate. And I have a typo (`ref` keyword is missing before `a`). – Leri Jan 15 '13 at 08:41
  • As Nathanael commented, this answer is obolsete, C# now supports the"this ref" argument. – Wilem2 Aug 20 '21 at 15:58
6

Old question, but on newer versions of C# it looks like you can now do this for value types by using the this and ref keywords together. This will set value to be the same as valueToChange, even outside of this extension method.

public static void ChangeValue(this ref int value, int valueToChange)
{
    value = valueToChange;
}

I believe this change was made to the compiler on version 15.1, which I think corresponds to C# 7 (or one of its sub versions). I did not immediately find a formal announcement of this feature.

Nathanael
  • 194
  • 2
  • 5
  • Note: the compiler error if the value ('asd') is 'temporary' i.e. a value from a getter. Don't be like me and write a lot of code and then discover it won't work. In the end, I wrote both a 'ref' and a 'non-ref' version. The 'ref' version may simply called the 'non-ref' version. – fishjd Apr 12 '23 at 23:20
1

According to this answer: https://stackoverflow.com/a/1259307/1945651, there is not a way to do this in C#. Primitive types like int are immutable, and cannot be modified without an out or ref modifier, but the syntax won't allow out or ref here.

I think your best case is to have the extension method return the modified value instead of trying to modify the original.

Apparently this is possible in VB.NET and if you absolutely needed it, you could define your extension method in a VB.NET assembly, but it is probably not a very good practice in the first place.

Community
  • 1
  • 1
JLRishe
  • 99,490
  • 19
  • 131
  • 169
1

I know it's too late, but just for the record, I recently really wanted to do this, I mean...

someVariable.ChangeValue(10);

...apparently looks way neat than the following (which is also perfectly fine)

ChangeValue(ref someVariable, 10);

And I managed to achieve something similar by doing:

public class MyClass
{
    public int ID { get; set; }
    public int Name { get; set; }
}

public static void UpdateStuff(this MyClass target, int id, string name)
{
    target.ID = id;
    target.Name = name;
}

static void Main(string[] args)
{
    var someObj = new MyClass();    

    someObj.UpdateStuff(301, "RandomUser002");
}

Note that if the argument passed is of reference type, it needs to be instantiated first (but not inside the extension method). Otherwise, Leri's solution should work.

Community
  • 1
  • 1
Yom T.
  • 8,760
  • 2
  • 32
  • 49
0

Because int is value type, so it copied by value when you pass it inside a function.

To see the changes outside of the function rewrite it like:

public static int ChangeValue(this int value, int valueToChange)
{
    //DO SOMETHING ;

    return _value_; //RETURN COMPUTED VALUE 
}

It would be possible to do using ref keyowrd, but it can not be applied on parameter with this, so in your case, just return resulting value.

Tigran
  • 61,654
  • 8
  • 86
  • 123