开发者

When to pass ref keyword in

开发者 https://www.devze.com 2022-12-18 19:34 出处:网络
I\'ve read the difference between passng and not passing ref in parameters, however, when would I want to use them?

I've read the difference between passng and not passing ref in parameters, however, when would I want to use them?

For example, I had some logic in a method which could be refactored into its own method. Resharper 4.5 made o开发者_如何转开发ne of the parameters a ref type but I didn't think I would have of done this if I did the refactoring manually.

Obviously I am missing some understanding. Perhaps an example of what happens when certain types or certain scenarios in coding miss the ref keyword will help?

Thanks


Let me break that down into two questions:

1) When should one use ref/out formal parameter declarations when writing a method?

Use ref/out when you desire your method to be able to read and write a variable passed in from the caller, rather than merely reading a value.

2) Why does an "extract method" refactoring produce a ref parameter?

I don't know the details of Resharper, but I can make a guess. Consider the following evil mutable value type:

struct S 
{ 
  private int x;
  public int X() { return this.x; } 
  public void M() { this.x += 1; } 
}

You have a method:

void Foo() 
{
    S s = new S();
    Fred(s);
    Blah(s);
    Bar(s);
    s.M();
    Console.WriteLine(s.X()); // prints 1
}

and you do "extract method" on the middle bit:

void NewMethod(ref S s)
{
    Blah(s);
    Bar(s);
    s.M();
}

void Foo() 
{
    S s = new S();
    Fred(s);
    NewMethod(ref s);
    Console.WriteLine(s.X()); // still prints 1
}

If instead you made a method without "ref" then calling NewMethod(s) would pass a copy of s to NewMethod. Remember, value types are copied by value; that's why we called them "value types". It would be the copy that gets mutated, and then s.X() returns zero. It is a bad idea for a refactoring to introduce a semantic change in a program, and it is difficult for a refactoring engine to know whether a given method relies on the mutability of a value type or not.

This is just another reason why you should avoid mutable value types.


Passing byref makes sense only for "side effects" of a function: i.e., you intend to modify a value-type parameter, or reassign another object to a given object parameter, and have that change survive the function call. Example: TryGetValue().

Otherwise, best to stick with byval.


I use references for semantics. Consider this approach:

void AddResultsTable(ref PlaceHolder p) // modifies p; adding a table
{
    var t = new Table();

    AddTableHeader(ref t); // modifies t; adding a table header

    AddTableBody(ref t);  // modifies t; adding a table body

    AddTableFooter(ref t);  // modifies t; adding a table footer

    p.Controls.Add(t);
}

AddResultsTable(ref PlaceHolderResults);

Versus this one:

Table ReturnTable()
{
    var t new Table();

    // AddTableHeader() returns TableHeader
    t.Columns.HeaderColumns.Add(ReturnTableHeader());

    // ... etc.

    return t;
}

PlaceHolder.Controls.Add(ReturnTable());

The first snippet of code looks cleaner to me; methods modifies objects rather than returning new object(s) which you in turn have to add. It all stays "boxed in" and hidden, inside the methods.


Conceptually, the difference is that a value type stores its value directly, whereas a reference type stores a reference to the value. Maybe you should re-read a bit about reference vs value types.

Passing value types by reference--as demonstrated above--is useful, but ref is also useful for passing reference types. This allows called methods to modify the object to which the reference refers because the reference itself is being passed by reference. The following sample shows that when a reference type is passed as a ref parameter, the object itself can be changed.

   class RefRefExample
{
    static void Method(ref string s)
    {
        s = "changed";
    }
    static void Main()
    {
        string str = "original";
        Method(ref str);
        // str is now "changed"
    }
} 

MSDN


The effect is that any changes to the parameter in the method will be reflected in that variable when control passes back to the calling method. So if you want the value assigned to the parameter to survive past the method call it's a possible usecase


Consider this example:

static int i = 3;

public static void ChangeIntRef(ref int val)
{
   val = 5;
}

public static void ChangeInt(int val)
{
   val = 5;
}

Console.WriteLine(i);
ChangeInt(i);
Console.WriteLine(i);

ChangeIntRef(ref i);
Console.WriteLine(i);

By passing the parameter as ref, you are telling the compiler that what you actually want is a reference to the original variable to be passed to the method. As a result, the method can change the value of the original variable.

If you run the snippet from above, the result is:

3
3
5

This should clearly show that without the ref keyword, the ChangeInt method is not able to actually change the original value. However, with the ref keyword the ChangeIntRef method is able to change the original value.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号