程序中的空例外

时间:2013-01-20 10:38:40

标签: c#

我有这样的程序

    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;
            }
        }
    }

输出:

  

对象引用不设置对象的实例

为什么呢? 当我在Test中设置objtest = null;时它会向我显示值,但是当我在同一时间设置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”??

3 个答案:

答案 0 :(得分:1)

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

我将在这里给出一个相当简短的答案;那些有兴趣了解更多和更深入的人非常欢迎阅读Jon Skeet关于Parameter passing in C#的文章和similar article的图表,由Lee Richardson撰写。

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

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

当你有这一行时:

test objtest = new test();

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

objtest.Name = "vikas";

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

当你有这样的功能签名时:

private static void Test(test objtest)

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

objtest.Name = "chetan";

与在函数外部使用它完全相同:它将在传递的内存地址中查找为属性 Name 保留的位置,并将其中的内容更改为“chetan”。同样,这种变化对于那个例子来说是直接和永久的。对于这件事(更改属性),如果您正在使用ref,则无关紧要,因为您正在处理引用类型。

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

objtest = null;

您将副本更改为无点,但函数外部的变量仍指向同一地址,且不会为空。

如果你有这样的功能签名:

private static void Test(ref test objtest)

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

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

答案 1 :(得分:0)

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

默认参数按值传递。

尝试将参数重新分配到其他内存位置只能在方法Test内部使用,并且不会影响Main方法中的原始变量objtest

因此,当您将ref添加到Test函数中的参数时,在两种情况下行为将是相同的,因为方法Test内发生的所有更改都会影响原始对象主方法中的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设置为原始对象,之后您需要读取属性Name,因此您将获得NullReferenceException

答案 2 :(得分:0)

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

您在访问objtest属性之前将null设置为Name,因此您尝试访问存储在地址零处的对象的Name属性,这毫无意义。