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 开发者_StackOverflow社区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?
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
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.
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.
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.
精彩评论