我有这样的程序
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”??
答案 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
属性,这毫无意义。