Difference between passing a reference type and a value type as argument to a method

后端 未结 3 1702
孤城傲影
孤城傲影 2021-01-29 07:34

Just got this confusion running in my mind throughout the day. I am very much confused between reference and value type being passed to a method.

Say I have 2 classes

相关标签:
3条回答
  • 2021-01-29 07:43

    In c#, all arguments sent to method are passing by value, unless they are passed using either the ref or out keywords.

    This includes arguments that are value types, reference types, mutable and immutable types.

    When passing a reference type argument to a method, what actually happens is that the reference of the argument is passed by value.

    This means that the method actually holds a new reference to the argument passed to it.
    So any change to that argument's state will be also reflected when using the reference from outside the method.
    However, when assigning a new value to the reference inside the method, it will not reflect on the reference outside the method.

    For a better, more extensive explanation, read Jon Skeet's Parameter passing in C# article.

    You can't test this using any immutable type, since immutable types, by definition, can't be changed.

    You can, however, test this with any mutable type:

    public static void Main()
    {
        var x = new List<int>();
        x.Add(1);
        Add(x, 2);
        Console.WriteLine(x.Count.ToString()); // will print "2";
        AddRef(ref x, 3);
        Console.WriteLine(x.Count.ToString()); // will print "1";
        Add3(x, 1, 2, 3 );
        Console.WriteLine(x.Count.ToString()); // will also print "1";
        Add3Ref(ref x, 1, 2, 3 );
        Console.WriteLine(x.Count.ToString()); // will print "3";
    }
    
    static void Add(List<int> list, int value)
    {
        // adding an item to the list, thus chaning the state of the list.
        // this will reflect on the list sent to the method, 
        // since a List is a reference type.
        list.Add(value);
    }
    
    static void AddRef(ref List<int> list, int value)
    {
        list = new List<int>(); // same as the s += “Hi”; in the question
        // Adding the value to the list.
        // Note that this change will reflect on the list passed to the method,
        // since it is passed using the ref keyword.
        list.Add(value);
    }
    
    
    static void Add3(List<int> list, int value1, int value2, int value3)
    {
        list = new List<int>(); // same as the s += “Hi”; in the question
    
        // these values are added to the new list.
        // since the reference to the list was passed by value,
        // it WILL NOT effect the list sent to the method.
        list.Add(value1); 
        list.Add(value2);
        list.Add(value3);
    }
    
    static void Add3Ref(ref List<int> list, int value1, int value2, int value3)
    {
        list = new List<int>(); // same as the s += “Hi”; in the question
        // these values are added to the new list.
        // since the list was passed by reference,
        // it WILL effect the list sent to the method.
        list.Add(value1);
        list.Add(value2);
        list.Add(value3);
    }
    

    You can see for yourself on this fiddle.

    0 讨论(0)
  • 2021-01-29 07:51

    Beside Reference Type and Value Type, there are Mutable Type and Immutable Type.

    Immutable means that object cannot and will not be changed after initialization. As a result, your statement only produces new string but does not modify original string.

    s += "Hi";

    The hello string object remains hello. Change is that s is assigned with a new object helloHi.


    You are unfortunate enough using string as an example.

    Try to use mutable types like StringBuilder in your example.

    public class C
    {
        public static void Main(string[] args)
        {
            StringBuilder s = new StringBuilder("hello");
            StringBuilder w = Changestring(s);
            StringBuilder x = s;
        }
    
        private static StringBuilder Changestring(StringBuilder s)
        {
            s.Append("Hi");
            return s;
        }
    }
    
    0 讨论(0)
  • 2021-01-29 07:59

    First to know, passing by value doesn't change initial variable value, where passing by reference also changes initial variable value referenced by method.

    By default int treated as value type, thus it is passed by value. However, a String even declared as a class (reference type), it is immutable by default with sealed modifier, thus treated as passing by value and adding new characters just create new instance of String, not changing current one.

    By adding ref keyword you can change int behavior to passing-by-reference:

    public Class B
    {
        public static void main(string[] args)
        {
            int s = 99;
            int w = Changeint(s); // w has changed
            int x = s; // s has also changed
        }       
    
        private int Changeint(ref int s)
        {
                s += 30; // result = 129
                return s;
        }
    }
    

    For class A, you need a StringBuilder instance to accomplish "helloHi":

    public Class A
    {
        public static void main(string[] args)
        {
            String s = “hello”;
            String w = Changestring(s);
            String x = w; // if you assign s to x, you will just get "hello"
        }
    
        private string Changestring(string s)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(s);
            sb.Append(“Hi”);
            return sb.ToString(); // "helloHi"
        }
    }   
    

    CMIIW.

    0 讨论(0)
提交回复
热议问题