Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How best to modify and return a C# argument?

I need to take a Widget that already has several property values set. I need to change the Widget's name. I'm drawn toward Option 3, but I'm having a hard time articulating why.

public void Do(Widget widget) { // 1
    widget.Name = "new name";
}

public void Do(ref Widget widget) { // 2
    widget.Name = "new name";
}

public Widget Do(Widget widget) { // 3
    widget.Name = "new name";
    return widget;
}

I'd like to play Devil's Advocate with a few questions and gather responses, to help me explain why I'm drawn to Option 3.

Option 1 : Why not just modify the Widget that's passed in? You're only "returning" one object. Why not just use the object that's passed in?

Option 2 : Why not return void? Why not just communicate in the signature that you'll be using the actual memory pointer to the parameter object itself?

Option 3 : Isn't it weird to you that you're returning the same object you're passing in?

like image 266
lance Avatar asked Sep 22 '11 15:09

lance


People also ask

Can AC function return different types?

No, you can't return multiple types. IMO you should rethink your design. Return a dynamically-allocated variant type.

What does it mean to return something in C?

A return statement ends the execution of a function, and returns control to the calling function. Execution resumes in the calling function at the point immediately following the call. A return statement can return a value to the calling function.

How does return work in C?

The return statement returns the flow of the execution to the function from where it is called. This statement does not mandatorily need any conditional statements. As soon as the statement is executed, the flow of the program stops immediately and returns the control from where it was called.

What is the use of return 0 in C?

C++ return 0 in the main function means that the program executed successfully. return 1 in the main function means that the program does not execute successfully and there is some error.


4 Answers

Option 1: This is the most common approach - you do not need ref if you don't want to modify the reference itself. Make sure that you name your method appropriately so the expectation is that the passed object is indeed modified.

Option 2: This is only useful if you want to change the passed reference itself, i.e. create a new Widget instance or set the reference to point to an existing widget (this might be useful if you want to keep overall number of instances low if they all have the same properties, see Flyweight pattern, generally the returned widgets should be immutable in this case though and you would use a factory instead). In your case this does not seem appropriate.

Option 3: This allows for a fluent "builder" approach - also has its benefits, i.e chaining of changes to the Widget which some people consider more expressive and self-documenting. Also see Fluent interface

like image 103
BrokenGlass Avatar answered Oct 26 '22 10:10

BrokenGlass


Option 1:

Fine. Exactly what I'd use. You can mutate the content of the widget, but not the widget itself.

Option 2:

No. No. No. You don't modify the reference itself, so you don't need to use ref. If you modified the reference itself (for example widget = new Widget() then out/ref are the correct choices, but in my experience that's rarely necessary.

Option 3:
Similar to option 1. But can be chained in a fluent style API. Personally I don't like this. I only use that signature if I return a copy and leave the original object untouched.


But the most important thing here is how you name the method. The name needs to clearly imply that the original object is mutated.

In many situations I'd opt for Option 4: Make the type immutable and return a copy. But with widgets which obviously are entity and not value like, this makes no sense.

like image 38
CodesInChaos Avatar answered Oct 26 '22 09:10

CodesInChaos


There isn't actually any functional difference between the 3 options. (There ARE differences, just none that are relevant to your question.) Keep it simple - use option 1.

like image 23
Michael Bray Avatar answered Oct 26 '22 10:10

Michael Bray


I think Option 1 and Option 3 are both viable options. Option 3 has the benefit of being self-documenting in that it implies that you are modifying Widget in the method. I think the worst option is Option 2. The ref keyword to me implies that you are modifying the reference of the object, which you are most certainly not doing.

like image 32
skaz Avatar answered Oct 26 '22 10:10

skaz