改了一句,运行结果为什么不同??

崔鹏飞 2008-08-26 09:18:04
就是这两句:s = new Student("li4");
//s.Name = "li4";
s = new Student("li4");的话就输出zhang3

s.Name = "li4";的话就输出li4

why????

class Student
{
private string name;

public string Name
{
get { return name; }
set { name = value; }
}

public Student(string _name)
{
name = _name;
}
static void Main()//Main_4_3_4
{
Student s = new Student("zhang3");
ChageName(s);
Console.WriteLine(s.Name);
Console.Read();
}

static void ChageName( Student s)
{
s = new Student("li4");
//s.Name = "li4";
}


}
...全文
312 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
chehongzhi 2009-06-30
  • 打赏
  • 举报
回复
按值传递引用类型,顾名思义,s的值传入ChangName()方法了,而s的引用却没有。 因此改动s=new Student("li4")想把s重新定向是痴人做梦,s的引用根本没传进来,怎么重定向?

而s的值传入ChangName()方法了,所以改动s.Name="li4";是有效的。
lz_0618 2008-08-28
  • 打赏
  • 举报
回复
我明白了,这不是C#的Bug,只是C#和C++中的概念不是一样的!

对于C#来说,当参数前不加ref或out是按值传递的,但对于参数是值类型和参数是引用类型的参数其表现是不一样的。对于引用类型,对于引用本身是按值传递的(不加ref时),所以s = new Student("li4"); 不会影响Main()函数中引用s指向的内存位置,所以返回时Main()函数中引用s所指向的内容是不会改变的,但当“s.Name = "li4";”时,由于Main()函数中引用s和ChageName函数中的S指向的是同一个内存位置,所以实际上把Main()函数引用s指向的内容改变了!!!

当加上ref或out后“引用参数”本身是按引用(地址)传入的,这时Main()函数和ChageName函数中的S似乎就是一个东西(也许实际上ChageName函数内的s是Main()函数中s引用的引用)。

在C++中ChageName(Student s),就是整个对象的传值, C++中会把Student 对象通过拷贝构造函数复制一份,所以从表面看和C#的表现不一样的,所以从C++转到C#的程序员,在这里可要注意了!

以上是我的理解,也许有不对的地方

下面是Effective C#中对“值类型和引用类型”的描述:
http://dev.yesky.com/msdn/47/3494047.shtml
崔鹏飞 2008-08-27
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 vrhero 的回复:]
这时:是把原本指向zhang3的s指向了li4
------
不对...new Student("li4")产生新的实例...它和你“原本指向zhang3的s”没有任何关系...

3、4楼解释的很清楚了...
[/Quote]
原本指向zhang3的s我说的这个s是static void ChageName( Student s)里面的参数s......
崔鹏飞 2008-08-27
  • 打赏
  • 举报
回复
谢谢16L
我知道ref或者out是按引用传参
我主要是问一下12楼的解释对不对啊...
luozuguo 2008-08-27
  • 打赏
  • 举报
回复
还是引用的问题
3楼说得没错,你把Main方法的 Console.WriteLine(s.Name)语句放到 ChageName方法里再跑一遍看看区别就知道了
vrhero 2008-08-27
  • 打赏
  • 举报
回复
这时:是把原本指向zhang3的s指向了li4
------
不对...new Student("li4")产生新的实例...它和你“原本指向zhang3的s”没有任何关系...

3、4楼解释的很清楚了...
崔鹏飞 2008-08-27
  • 打赏
  • 举报
回复
static void ChageName( Student s)
{
s = new Student("li4");
}

这时:是把原本指向zhang3的s指向了li4

而下面:
static void ChageName( Student s)
{
s.Name = "li4";
}

这个型参s和实参s是指向同一个zhang3,而这样一操作就变成了li4


请大家看一下解释的对不对
对的话就结贴了
setdefault 2008-08-27
  • 打赏
  • 举报
回复

class Student
{
private string name;

public string Name
{
get { return name; }
set { name = value; }
}

public Student(string _name)
{
name = _name;
}
static void Main()//Main_4_3_4
{
Student s = new Student("zhang3");
ChageName(out s);
Console.WriteLine(s.Name);
Console.Read();
}

static void ChageName(out Student s)
{
s = new Student("li4");
//s.Name = "li4";
}


}



参数加上out关键字就行
lz_0618 2008-08-27
  • 打赏
  • 举报
回复
怎么会这样,真奇怪了
崔鹏飞 2008-08-27
  • 打赏
  • 举报
回复
自己up
GhostAdai 2008-08-27
  • 打赏
  • 举报
回复
路过接分~By the way:以后尽量避免出现这种逻辑问题。
wxdd128 2008-08-27
  • 打赏
  • 举报
回复
static void ChageName( Student s)
{
s = new Student("li4"); // 生成新的副本,不会传递回调用的函数。
//s.Name = "li4"; // 没有生成新的实例,对传递进来的s赋值。
}

这个是正确的
lz_0618 2008-08-27
  • 打赏
  • 举报
回复
这实在是一个奇怪的问题,不知道是不是C#的BUG!!

同样的情况,我在VC++2008下试了一下,显示的都是zhang3,因为static void ChageName( Student s)传递参数定义的是传值,所以S在函数中怎么改变,应该回来后恢复原值,C++中是比较符合传值的本意的,在C#中确实出现楼主的问题!!!!!!

所以以后用C#编程要小心喽!!!!!!!!
崔鹏飞 2008-08-27
  • 打赏
  • 举报
回复
static void ChageName( Student s)
{
s = new Student("li4");
}
型参和实参原本都指向zhang3,运行s = new Student("li4");之后型参指向了li4,而实参仍然指向zhang3



而下面:
static void ChageName( Student s)
{
s.Name = "li4";
}
这个型参s和实参s是指向同一个zhang3,而这样一操作,实例的Name属性就从zhang3变成了li4
请大家看一下解释的对不对
我觉得这样解释似乎是和3、4L一致的
[/Quote]
spring20130808 2008-08-27
  • 打赏
  • 举报
回复
补充一下, 因为 s = new Student("li4");
所以s对象是个副本,对它的修改不会影响到Main()中的s变化的.如果想变化就用ref关键字把s作引用参数传递.
wackyboy 2008-08-27
  • 打赏
  • 举报
回复

static void ChageName(Student s) //形参是在栈上的实参的拷贝,和实参指向的是堆上的同一块区域。
{
s = new Student("li4"); //形参声明对象,形参指向新的地址,而是参没有变化
//s.Name = "li4"; //形参的Name变化,因为形参和实参指向的是堆上的同一块区域,所以形参的Name变化,同时实参的Name也变化
}

所以会出现楼主的结果。可以用ref / out进行强制引用
spring20130808 2008-08-27
  • 打赏
  • 举报
回复
static void ChageName( Student s)
{
s = new Student("li4");
//s.Name = "li4";
}
中的s对象的作用域(生命周期)仅限此方法中
原主函数中的不是同一个s.可能这么理解它们之间没关系的.
Odesky 2008-08-27
  • 打赏
  • 举报
回复
Console.Read();

只是单纯的接收
LuckyMouse_ZJU 2008-08-27
  • 打赏
  • 举报
回复
就是12楼的解释,这个是典型的值传递和引用传递问题啊!
你传进来的是一个引用(类似于c++地址),你只能改变这个引用的对象的值,不能改变这个引用本身。
所以:s=new() 新new的是传不出去的。
崔鹏飞 2008-08-26
  • 打赏
  • 举报
回复
按照我贴的代码来说:这是引用类型的按值传递吧?
引用类型的按值传递不应该改变s实例啊......
也就是说
s = new Student("li4");
s.Name = "li4";
两句都应该不改变s啊....
why not?
加载更多回复(4)

110,501

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧