21

在 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的相同的副本?或者这两个变量是否指向不同的对象实例?someTestObjMain

4

7 回答 7

21

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

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

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

于 2012-10-21T20:08:01.673 回答
12

对象将通过引用传递,而与同一类或另一个类的方法无关。这是相同示例代码的修改版本,以帮助您理解。该值将更改为“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();
       }       
    }
 }
于 2012-10-21T12:19:49.447 回答
6

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

换句话说,我的 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;
    }
}
于 2015-12-16T20:22:37.873 回答
5

假设someTestObj是 aclass而不是 a struct,则对象是通过引用传递的,这意味着两者obj和都someTestObj引用同一个对象。例如,改变name一个会改变另一个。但是,与使用ref关键字传递它不同,设置obj = somethingElse不会改变someTestObj

于 2012-10-21T12:09:30.757 回答
2

如果将 Object 作为值类型传递,则在方法内部对对象成员所做的更改也会在方法外部受到影响。但是如果对象本身被设置为另一个对象或重新初始化,那么它将不会反映在方法之外。所以我会说对象作为一个整体仅作为 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
}
于 2013-02-22T10:41:28.280 回答
0

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

这是参考的文章:深度克隆对象

于 2012-10-22T13:00:14.493 回答
0

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

于 2019-07-11T14:39:51.573 回答