0

我有这样的程序

    class Program
    {
        static void Main(string[] args)
        {
            test objtest = new test();
            objtest.Name = "vikas";
            Test(objtest);
            //objtest = null; when I uncomment this line it shows me exception
            Console.WriteLine(objtest.Name);
            Console.ReadLine();
        }

        private static void Test(test objtest)
        {
            objtest.Name = "chetan";
            objtest = null;
        }
    }

    class test
    {
        private string _Name = string.Empty;
        public string Name
        {
            get
            {
                return _Name;
            }
            set
            {
                _Name = value;
            }
        }
    }

输出:车坦

第二个程序:

    class Program
    {
        static void Main(string[] args)
        {
            test objtest = new test();
            objtest.Name = "vikas";
            Test(objtest);
            objtest = null;
            try
            {
                Console.WriteLine(objtest.Name);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.InnerException + " " + ex.Message);
            }

            Console.ReadLine();
        }

        private static void Test(test objtest)
        {
            objtest.Name = "chetan";
            objtest = null;
        }
    }

    class test
    {
        private string _Name = string.Empty;
        public string Name
        {
            get
            {
                return _Name;
            }
            set
            {
                _Name = value;
            }
        }
    }

输出:

对象引用不设置对象实例

为什么?当我objtest = null;在 Test 中设置时,它会显示值,但是当我将 null 设置为相同时,它会显示错误。

在@kmatyaszek 帖子之后添加:

在第一个程序中

static void Main(string[] args)
        {
            test objtest = new test();
            objtest.Name = "vikas"; // **I am assigning this value**
            Test(objtest);
            //objtest = null; when I uncomment this line it shows me exception
            Console.WriteLine(objtest.Name);
            Console.ReadLine();
        }

        private static void Test(test objtest)
        {
            objtest.Name = "chetan";
            objtest = null;
        }

为什么它显示“chetan”而不是“vikas”?

4

3 回答 3

1

由按值传递的引用类型引起的经典混淆。

我将在这里给出一个相当简短的答案;那些有兴趣了解更多和深入的人非常欢迎阅读由 Lee Richardson撰写的关于C# 中的参数传递的Jon Skeet 文章和类似的带有图表的文章。

简而言之,引用类型是任何非原始或结构的类型。因此,任何自定义类都是引用类型。

当将此类的实例传递给函数时,实际发生的是传递了指向该实例的指针。更准确地说,指针的副本正在传递,因为默认情况下参数是按值传递的。

当你有这条线时:

test objtest = new test();

test正在创建该类的新实例并在内存中分配地址。每次引用变量objtest时,都会使用该地址,例如:

objtest.Name = "vikas";

运行时引擎将转到创建实例时分配的地址,查找为属性名称保留的位置并将那里的内容更改为“vikas”。对于此实例,更改是即时且永久的。

当你有这样的函数签名时:

private static void Test(test objtest)

“幕后”传递的实际参数是内存中实例的地址。每当您在函数内部引用参数objtest时,运行时引擎都会转到作为实际参数传递的地址。所以在函数中有这一行:

objtest.Name = "chetan";

和把它放在函数外完全一样:它会在传递的内存地址中寻找为属性名称保留的位置,并将那里的内容更改为“chetan”。再一次,这种变化对于那个例子来说是立即和永久的。对于这件事(更改属性),您是否正在使用ref并不重要,因为您正在处理引用类型。

但是,按值传递(例如,没有ref关键字)意味着正在复制内存地址,而函数只获取副本,非常类似于传递整数。对副本的任何更改都不会影响原始值。因此,当您在函数中有此行时:

objtest = null;

您将副本更改为不指向任何内容,但是函数外部的变量仍然指向相同的地址并且不会为空。

如果您有这样的函数签名:

private static void Test(ref test objtest)

那么这意味着地址本身是通过引用传递的,因此更改保存地址的变量也会导致它在函数之外被更改。

这几乎总结了它,我没有在这里带来任何新东西,只是用我认为更简单的解释来澄清事情。

于 2013-01-21T15:45:54.350 回答
0

您在将参数传递给函数时遇到问题。

默认参数按值传递。

将参数重新分配到不同内存位置的尝试仅在方法内部起作用,Test并且不会影响objtestMain 方法中的原始变量。

因此,在两种情况下,当您ref在函数中添加参数时,Test行为将是相同的,因为方法内部发生的所有更改都会Test影响 Main 方法中的原始对象objtest

带有 ref 参数的问题的第一个示例:

 class Program
    {
        static void Main(string[] args)
        {
            test objtest = new test();
            objtest.Name = "vikas";
            Test(ref objtest);
            //objtest = null; when I uncomment this line it shows me exception
            Console.WriteLine(objtest.Name);
            Console.ReadLine();
        }

        private static void Test(ref test objtest)
        {
            objtest.Name = "chetan";
            objtest = null;
        }
    }

    class test
    {
        private string _Name = string.Empty;
        public string Name
        {
            get
            {
                return _Name;
            }
            set
            {
                _Name = value;
            }
        }
    }

在第二个示例中,首先将 null 设置为原始对象,然后您要读取属性名称,因此您将获得NullReferenceException.

于 2013-01-20T10:40:53.630 回答
0

好吧,您正在使用一个值为 的对象null,这会导致异常。null引用类型的意思是“指向零”。当您尝试访问存储在地址零处的值时,您会得到一个NullReferenceException.

您在访问该属性之前设置objtest为,因此您试图访问存储在地址零处的对象的属性,这是没有意义的。nullNameName

于 2013-01-20T11:19:29.373 回答