【问题标题】:why a class don't need to add ref? [duplicate]为什么一个类不需要添加参考? [复制]
【发布时间】:2018-03-14 07:24:53
【问题描述】:

类可以从方法中设置名称并保留值:示例

Employeer e  = new Employeer()
SetName(e);

但是我们在调用方法SetName(e)的时候不需要加ref 但是你需要添加一个字符串 ref

string name = "";
SetName(ref name);

谁能详细解释一下?谢谢

【问题讨论】:

    标签: c# asp.net


    【解决方案1】:

    这就是改变变量值和改变引用类型对象状态的区别。

    使用Employee,您正在执行后者。使用string,您正在做前者。

    使用引用类型,对对象的引用被复制和传递。这就是为什么您只需传递e 即可更改员工姓名的原因。但是,如果您在方法内重新分配 e 会怎样?

    // in the method
    e = null;
    

    传入的e会变成null吗?不,这是因为您将 已复制 引用指向其他东西。它与您创建员工时的原始参考无关。

    这和字符串是一样的,因为字符串也是一个引用类型。当您将传入的字符串更改为方法内的其他内容时:

    myString = "hello";
    

    更改不会反映在方法之外。理论上,您可以在方法内部改变字符串的状态,它会在方法外部反映。但是,字符串是不可变的(不会公开任何可以让您更改其状态的内容)。

    当您向其添加ref 时,可以这样做,因为它有点传递引用您对象的引用的引用。因此,您可以在方法内部重新分配内容,并且更改将反映在外部。

    【讨论】:

      【解决方案2】:

      如果您在方法调用期间没有使用 ref 关键字传递字符串,那么它会创建一个新的字符串实例,并对字符串的新实例进行更改。在返回方法后,我们传递的字符串值不受影响

      【讨论】:

        【解决方案3】:

        在 C# 中,字符串数据类型具有以下属性: • String 是一种引用类型,但其行为类似于值类型。 • 字符串是不可变的,即每次更改字符串时都会创建一个新字符串,并且引用变量会更改其对新创建字符串的引用。

        对象类型的引用变量总是通过引用传递(可能看起来很棘手,但如果你继续阅读,你会明白的:))。 但是在字符串的情况下,默认传递的引用变量是按值传递的(除非您明确使用了 ref 关键字)。 所以在以下情况下:

        String hello = "Hello";
        MyFunction(hello);
        

        将在 MyFucntion 中创建一个新的引用变量,该变量引用与 hello 字符串相同的位置。但是,当您更改 MyFucntion 中的 hello 函数时,实际上新创建的引用变量的内容将被更改。

        void MyFuntion(String hello)
        {
            //a new string will be created and the reference value of the 
            //local hello will be changed
            hello = "Bye";
        }
        

        让我们借助另一个示例来了解更多细节: 考虑以下代码:

        内部主要:

        //let's create a string and pass it to a function as value and reference type
        String str = "Hello World";
        StringRefernecePassedByValue(str, ref str);
        //the reference that was passed by value is the one that is the actual reference
        //other one was a new refernece variable that has a copy of the reference
        Console.WriteLine("Actual String: " + str);
        

        调用的函数:

        //The body of the function
        static void StringRefernecePassedByValue(String valStr,ref String refStr)
        {
            //Both of the passed reference variable are pointing to the same location
            Console.WriteLine("Are equal?: " + ReferenceEquals(valStr, refStr));
        
            //let's change the strings
            valStr = "Hello1";//a new string is created and now the valStr refer to it
            refStr = "Hello2";//a new string is created and now the refStr refer to it
        
            //let's confirm the output
            Console.WriteLine("Passed by Value: " + valStr);
            Console.WriteLine("Passed by Reference: " + refStr);
        
            //now both are changed are are no more refering to the same location
            Console.WriteLine("Are equal?: " + ReferenceEquals(valStr, refStr));
        }
        

        输出是:

        Are equal?: True
        Passed by Value: Hello1
        Passed by Reference: Hello2
        Are equal?: False
        Actual String: Hello2
        

        现在让我们为用户定义的类型执行上述操作:

        //a user defined datatype
        class Student
        {
            public String name { get; set; }
            public String cgpa { get; set; }
        }
        

        内部主要:

        //let's observe in case of Custom type
        Student student = new Student();
        student.name = "Ali";
        student.cgpa = "3.5";
        
        ClassRefernecePassedByValue(student, ref student);
        Console.WriteLine("Actual String: " + student.name);
        

        要调用的函数:

        //the body of function
        static void ClassRefernecePassedByValue(Student valStd, ref Student refStd)
        {
            //Both of the passed reference variable are pointing to the same location
            Console.WriteLine("Are equal?: " + ReferenceEquals(valStd, refStd));
        
            //let's change the objects
            valStd.name = "Joseph";//changing the object refered by valStd
            refStd.name = "Mick";//changing the object refered by refStd 
        
            Console.WriteLine("Passed by Value: " + valStd.name);
            Console.WriteLine("Passed by Reference: " + refStd.name);
        
            //now both are same
            Console.WriteLine("Are equal?: " + ReferenceEquals(valStd, refStd));
        }
        

        输出:

        Are equal?: True
        Passed by Value: Mick
        Passed by Reference: Mick
        Are equal?: True
        Actual String: Mick
        

        因此得出结论,当传递给函数时,对字符串的引用实际上会创建一个新的引用变量,其中包含对另一个字符串引用变量的复制引用,但由于字符串是不可变类型,因此当新引用变量指向的字符串发生变化时那么实际的参考变量保持不变。

        另外为了进一步了解你可以获取完整代码here

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-02-10
          • 1970-01-01
          • 2012-08-07
          • 1970-01-01
          • 2013-07-09
          • 1970-01-01
          • 2014-11-13
          相关资源
          最近更新 更多