C# ref keyword usage

后端 未结 7 1356
耶瑟儿~
耶瑟儿~ 2020-12-10 03:39

I understand (or at least I believe I do) what it means to pass an instance of a class to a method by ref versus not passing by ref. When or under

7条回答
  •  挽巷
    挽巷 (楼主)
    2020-12-10 04:29

    I found that it is easy to run into trouble using the ref keyword.

    The following method will modify f even without the ref keyword in the method signature because f is a reference type:

    public void TrySet(Foo f,string s)
    {
       f.Bar = s;
    }
    

    In this second case however, the original Foo is affected only by the first line of code, the rest of the method somehow creates and affects only a new local variable.

    public void TryNew(Foo f, string s)
    {
      f.Bar = ""; //original f is modified
      f = new Foo(); //new f is created
      f.Bar = s; //new f is modified, no effect on original f
    }
    

    It would be good if the compiler gave you a warning in that case. Basically what you are doing is replacing the reference you received with another one referencing a different memory area.

    It you actually want to replace the object with a new instance, use the ref keyword:

    public void TryNew(ref Foo f, string s)...
    

    But are you not shooting yourself in the foot? If the caller is not aware that a new object is created, the following code will probably not work as intended:

    Foo f = SomeClass.AFoo;
    TryNew(ref f, "some string"); //this will clear SomeClass.AFoo.Bar and then create a new distinct object
    

    And if you try to "fix" the problem by adding the line:

    SomeClass.AFoo = f;
    

    If the code holds a references to SomeClass.AFoo somewhere else, that reference will become invalid...

    As a general rule, you probably should avoid using the new keyword to alter an object which you read from another class or received as a parameter in a method.

    Regarding the use of the ref keyword with reference types, I can suggest this approach:

    1) Don't use it if simply setting the values of the reference type but be explicit in your function or parameter names and in the comments:

    public void SetFoo(Foo fooToSet, string s)
    {
      fooToSet.Bar = s;
    }
    

    2) When there is a legitimate reason to replace the input parameter with a new, different instance, use a function with a return value instead:

    public Foo TryNew(string s)
    {
      Foo f = new Foo();
      f.Bar = s;
      return f;
    }
    

    But using this function may still have unwanted consequences with the SomeClass.AFoo scenario:

    SomeClass.AFoo = TryNew("some string");//stores a different object in SomeClass.AFoo 
    

    3) In some cases such as the string swapping example here it is handy to use ref params, but just as in case 2 make sure that swapping the object addresses does not affect the rest of your code.

    Because it manages memory allocation for you, C# makes it all too easy to forget everything about memory management but it really helps to understand how pointers and references work. Otherwise you may introduce subtle bugs that are difficult to find.

    Finally, this is typically the case where one would want to use a memcpy like function but there is no such thing in C# that I know of.

提交回复
热议问题