对象作为参数传递给另一个类,通过值还是引用?

Posted

技术标签:

【中文标题】对象作为参数传递给另一个类,通过值还是引用?【英文标题】:Object passed as parameter to another class, by value or reference? 【发布时间】:2012-10-11 10:45:46 【问题描述】:

在 C# 中,我知道默认情况下,传递给函数的任何参数都是通过复制的,也就是说,在函数内部,存在参数的本地副本。但是,当一个对象作为参数传递给另一个类时呢?

像下面这样的场景是通过引用传递还是通过值传递:

class MyClass 
   private Object localObj;

   public void SetObject(Object obj) 
      localObj = obj;
   


void Main() 
   Object someTestObj = new Object();
   someTestObj.name = "My Name";
   MyClass cls = New MyClass();
   cls.SetObject(someTesetObj);

在这种情况下,类变量localObj 是否与在Main 驱动程序类中创建的someTestObj 具有相同的副本?或者这两个变量会指向不同的对象实例吗?

【问题讨论】:

“在 C# 中,我知道默认情况下,传递给函数的任何参数都将通过复制”,反之亦然。只有传递给函数的结构才会在函数范围内复制。对象总是通过引用,这意味着内存中只有一个版本,并且每个变量都指向它。 【参考方案1】:

“对象”永远不会在 C# 中传递——“对象”不是语言中的值。语言中唯一的类型是原始类型、结构类型等和引用类型。没有“对象类型”。

ObjectMyClass 等类型是引用类型。它们的值是“引用”——指向对象的指针。对象只能通过引用来操作——当你对它们执行new 时,你会得到一个引用,. 操作符对一个引用进行操作;等等。因为没有对象类型,所以无法获取其值“是”对象的变量。

所有类型,包括引用类型,都可以通过值或引用传递。如果参数具有 refout 之类的关键字,则通过引用传递参数。 SetObject方法的obj参数(属于引用类型)没有这样的关键字,所以是按值传递——引用是按值传递的。

【讨论】:

什么?错了,最后一行没有意义。对象总是通过引用(句点)传递。 @States: 不,“对象”不是 C# 中的值,不能“通过”。 struct 的实例不是对象吗?这些是按值传递的 是的,结构是值类型,对象是引用类型。就那么简单。如果您想了解更多关于何时适用的信息,有很多关于该主题的文章,Microsoft Docs 中的这篇文章就是一个很好的例子。 docs.microsoft.com/en-us/dotnet/standard/design-guidelines/…【参考方案2】:

对象将通过引用传递,与同一类或另一个类的方法无关。这是相同示例代码的修改版本,以帮助您理解。该值将更改为“xyz”。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace ConsoleApplication1

    public class Employee
    
        public string Name  get; set; 
    

    public class MyClass
    
        public Employee EmpObj;

        public void SetObject(Employee obj)
        
            EmpObj = obj;
        
    

    public class Program
    
       static void Main(string[] args)
        
            Employee someTestObj = new Employee();
            someTestObj.Name = "ABC";

            MyClass cls = new MyClass();
            cls.SetObject(someTestObj);

            Console.WriteLine("Changing Emp Name To xyz");
            someTestObj.Name = "xyz";

            Console.WriteLine("Accessing Assigned Emp Name");
            Console.WriteLine(cls.EmpObj.Name); 

           Console.ReadLine();
              
    
 

【讨论】:

对象不是通过引用传递的。引用是按值传递的。这是一个很大的区别,重要的是要清楚这一点,IMOI。 默认情况下,对象是通过值而不是通过引用传递的,我们使用(ref object)通过引用传递对象【参考方案3】:

我发现其他示例不清楚,所以我做了自己的测试,确认类实例是通过引用传递的,因此对类执行的此类操作将影响源实例。

换句话说,我的 Increment 方法每次调用时都会修改它的参数 myClass。

class Program

    static void Main(string[] args)
    
        MyClass myClass = new MyClass();
        Console.WriteLine(myClass.Value);  // Displays 1
        Increment(myClass);
        Console.WriteLine(myClass.Value);  // Displays 2
        Increment(myClass);
        Console.WriteLine(myClass.Value);  // Displays 3           
        Increment(myClass);
        Console.WriteLine(myClass.Value);  // Displays 4
        Console.WriteLine("Hit Enter to exit.");
        Console.ReadLine();
    

    public static void Increment(MyClass myClassRef)
    
        myClassRef.Value++;
    


public class MyClass

    public int Value get;set;
    public MyClass()
    
        Value = 1;
    

【讨论】:

【参考方案4】:

假设someTestObjclass 而不是struct,则对象通过引用传递,这意味着objsomeTestObj 都引用同一个对象。例如。在其中一个中更改name 将在另一个中更改它。但是,与使用ref keyword 传递它不同,设置obj = somethingElse 不会改变someTestObj

【讨论】:

【参考方案5】:

如果作为值类型传递一个对象,那么在方法内部对对象成员所做的更改也会在方法外部受到影响。 但是如果对象本身被设置为另一个对象或重新初始化,那么它不会反映在方法之外。所以我会说对象作为一个整体仅作为 Valuetype 传递,但对象成员仍然是引用类型。

private void button1_Click(object sender, EventArgs e)

    Class1 objc ;
    objc = new Class1();
    objc.empName = "name1";
    checkobj(objc);
    MessageBox.Show(objc.empName);  //propert value changed; but object itself did not change


private void checkobj (Class1 objc)

    objc.empName = "name 2";
    Class1 objD = new Class1();
    objD.empName ="name 3";
    objc = objD ;
    MessageBox.Show(objc.empName);  //name 3

【讨论】:

【参考方案6】:

如果需要复制对象请参考对象克隆,因为对象是通过引用传递的,顺便提一下性能好,对象创建成本高。

这里有文章可以参考:Deep cloning objects

【讨论】:

【参考方案7】:

通常,“对象”是类的实例,它是在内存中创建的类的“图像”/“指纹”(通过 New 关键字)。 对象类型的变量指的是这个内存位置,也就是它本质上包含了内存中的地址。 因此,对象类型的参数将引用/“链接”传递给对象,而不是整个对象的副本。

【讨论】:

以上是关于对象作为参数传递给另一个类,通过值还是引用?的主要内容,如果未能解决你的问题,请参考以下文章

将方法作为 SEL 参数传递给另一个类方法

如何将数组的值作为第二个参数传递给 awk 的 split 函数?

如何将向量作为参数传递给另一个向量?

是否可以将类类型的对象作为参数传递给另一个类,这样我就不必再次初始化? (Python 3.x)

C++ 将列表作为参数传递给函数

当我们将对象作为参数传递给方法时,为啥会调用复制构造函数?