偶当时的看法是:由于object是一个类,类的运算符需要定义,它的比较是定义(重载)运算符的问题.但是有一点又说不通了.因为在VS2002里,((object)s == (object)t)是真而在Console输出时((object)s == (object)t)却是假,这就让人琢磨不透里面有什么东东了.
解决方案 »
- 如何读取必须登录后才能显示的网页的源代码
- 第一次做winfrom开发,麻烦进来看看,打开新窗口关闭当前窗口的问题,谢谢
- 请问怎样用一个WinForm打开另一个WinForm后,两个Form之间可以互相设置控件的值?
- 请教new和override
- 如何使用webrequest 用异步的方式的得到一个网页的文本
- 动态改变数组的长度
- 如何:定位并修改datatable中某一行的数据
- 安装部署问题(连接数据库的字符串在安装的时候由用户输入,动态的写到XML(xml为连接数据库的配置文件))
- 如何在formview中的insertItem模板下实现textbox点击自动计算
- combox 怎么绑定到一个datetable?
- 服务管理器中的SQLSEVER启动不了。各位大哥救我
- 运行一个存储过程(耗时30秒),发生错误,请高手指点!
我刚刚测试,((object)s == (object)t)为falseif((object)s == (object)t)
{
Console.WriteLine((object)s == (object)t);
}
监视object类型的时候,这个object类型很有意思,
试试((object)s)看看.里面就只含了一个值.string "Test"有意思的地方是在
Console中,输出的结果是false
而VS的跟踪始终是true
Console中,输出的结果是false
而VS的跟踪始终是true
-->>我跟踪的时候就是false,所以输出的也是falseCLR Debuger--〉〉这个我没用过!咋用!?
t只是copy了s的value, 不是reference.(string)s == (string)t
比较的是value(object)s == (object)t
比较的是reference当然是FalseStirng是比较经典的不变模式,C#与Java的设计上差不多, 你可以参看Java中相关String类的sourcecode.
首先必须明确CTS System.String类型是一个引用类型。
string s = "Test";
给s赋值。s在栈中指向堆中占的一个空间。堆中的值是"Test"
string t = string.Copy(s);
给t赋值。t在栈中指向堆中占的一个新空间。堆中的值是"Text"
(Copy方法创建了新实例)Console.WriteLine(s == t);
由于"=="默认没有对string重载,所以比较的是s对象和t对象在堆中的地址。
此是为falseConsole.WriteLine(((object)s).ToString ());
这里先把s转成object型,再利用object的ToString方法把对象的值转成字符显示出来。Console.WriteLine(((object)s).Equals (((object)t)));
这里把s和t转成object之后再进行比较,由于此方法以默认重载,所以在此是比较s和t的值。
此为TureConsole.WriteLine((string)s == (string)t);
把对象转为字符进行比较,但用的是"=="号,虽然没有重载但由于比较的是值,所以
此为TureConsole.WriteLine((object)s == (object)t);
比较引用,肯定不同,因为前面的Copy实际上在2个地方放置了对象。
偶的问题是.单步跟踪(object)s == (object)t 时候,启动程序从string t = string.Copy(s);一句开始,监视的值就一直为True.而最后一句话中Console的输出却是False.
记得我以前在VB里调试程序的时候,总是当某行执行过以后才可以利用调试器看出结果,估计是比较之前返回值为True,为何不在比较以后再查看那一行的结果呢?
针对这个问题:
因为在VS2002里,((object)s == (object)t)是真
请确定“=”没有没重载过,因为“=”被重载后“==”会被自动重载。
就象“+”被重载后“+=”会被自动重载一样。
因为在VS2002里,((object)s == (object)t)是真
请确定Equals, “==”和“!=”没有被重载过。
并且赋值时确定是以传值的方式赋值,而非传引用。
((string)s==(string)t)和(s==t)也是值比较,为true.
((object)s==(object)t)是引用比较,是false.
在跟踪(object)s == (object)t 时候,总是显示true,它和输出的结果是两回事.
在.net中,string是不能改变的,crl只为同样的string分配一块内存.所以总是显示true,但程序执行到((object)s==(object)t)时两个的句柄不同,输出false.这个问题的关键是(object)s取的是引用句柄,而不是物理地址.
string[] a=new string[1000000];
for (int i=0;i<=999999;i++)
a[i]="abcdefghigklmnopqrstuvwxyz";
在程序里加以上语句,a[0]和a[1]的引用句柄不同,如果全部单独分配内存的话,算来这个字串要占26M内存,但在任何程序里加上看一下,然后再注释掉看一下,所点内存内乎完全一样,说明从a[0]到a[999999]全是使用的是同一内存地址.但是(object)a[0]==(object)a[1]却是false的.
{
static void Main()
{
object s = "Test"; object t = "Test"; Console.WriteLine(s == t);
}
}
这个为什么相等呢?
string类型确实是引用类型,当你这样赋值时
string s="Test";
string t="Test";
它确实是指向同一地址,所以:
((object)s==(object)t)为True.当
string s="Test";
string t="Test1";时
((object)s==(object)t)为Flase当string s="Test";
string t=string.Copy(s); 时,由于Copy明确告诉编译器要复制值,所以为Flase.如果是其他基本类型如int,
int s=1;
int t=1;
((object)s==(object)t)为Flase
using System;namespace ConsoleApplication1
{
/// <summary>
/// Class1 的摘要说明。
/// </summary>
class Class1
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
string s = "Test";
string t = string.Copy(s);
Console.WriteLine(s == t);
Console.WriteLine(((object)s).ToString ());
Console.WriteLine(((object)s).GetHashCode());
Console.WriteLine(((object)t).GetHashCode());
Console.WriteLine(((object)s).Equals (((object)t)));
Console.WriteLine((string)s == (string)t);
Console.WriteLine((object)s == (object)t); t = "Test";
Console.WriteLine((object)s == (object)t);
t=t+"d";
t=t.Substring(0,t.Length-1);
Console.WriteLine((object)s == (object)t);
Console.ReadLine();
} }
}
t = "Test";
Console.WriteLine((object)s == (object)t);
t=t+"d";
t=t.Substring(0,t.Length-1);
Console.WriteLine((object)s == (object)t);
Console.ReadLine();偶感觉 好像是内存分配的问题.不是运算符重载的问题.
第一部分:
t = "Test";
Console.WriteLine((object)s == (object)t);
返回True
意料之中,也是意料之外.第二部分
t=t+"d";
t=t.Substring(0,t.Length-1);
Console.WriteLine((object)s == (object)t);
Console.ReadLine();
是对字符串操作了之后,重新得值.结果是False
所以,这次比较应该有关内存地址的比较.
记不清是不是以前看Begining C# 中好像提过类似的事---关于内存分配
越试越 汗........
Console.WriteLine((object)s == (object)t);
返回True这是因为,字符串在处理时,如果没有进行操作,就直接指向那个内存地址值.
而在
t=t+"d";
t=t.Substring(0,t.Length-1);
Console.WriteLine((object)s == (object)t);
这里时,
由于字符串内容发生变化,所以,CLR会重新给t分配一块内存.
这时再用Console.WriteLine((object)s == (object)t);
比较时,就是False了,因为它们引用的内存地址不一样.为什么在VS2002监视时,会是True呢?
其实也很简单.
是因为,VS2002它在Debug时,对于
(object)s == (object)t
中的
(object)s (或(object)t)
来说,里面只有一个String "Test"
也就是说(object)s能让VS2002看到的只有这么一个东西.
所以比较时,也就返回True了.
所以.....
To楼主:对于专家分来说,偶就不要了,偶看见这里全是星星,所以分也没什么意思,就送给我们的杨秘书吧.再多点更好.你这个题目真的不只20分的.呵呵,各位见笑了.
回去写了一些程序,查看了IL,果然存在这种现象。楼主说的应该是因为虚拟机的字符串优化策略有关。由于string是一种不变体,虚拟机会把代码中显式定义的字符串缓存到“字符串池”公用。如有:
string str1 = "abc";
string str2 = "def";
string str3 = "abcdef";那么string对象"abc"、"def"、"abcdef"将存在于“字符串池”中
现在我在定义:
str4 = "abcdef"; //这里产生IL: ldstr "abcdef" 虚拟机执行为使用“字符串池”中的对象。
实际上str4引用str3同一个对象。所以(object)str3 == (object)str4地址相等。但
str5 = str1 + str2
(object)str5 != (object)str3,因为str5是经过运算构造出来的新对象。
同样谢谢:hyifeng() ,loulanlouzhu(桃花潭水深千尺,不及阿勇念你情),aspcn(飞刀),SimerJoe(浪月), zhouqi66(部落),c5n() 本着女士优先的CSDN男士风度来说,雍软(珠海)的 SolidGL(雍软(珠海)研发中心核心成员) 更是让偶钦佩之至。所以,致谢的话要说。专家分分之则太少,合之还差不多。不过,妖精,问是你提出来的,虽然 SolidGL(雍软(珠海)研发中心核心成员) 是你的同事,但也请你感谢一下他。这样式,偶给分就给的心安了。555偶要重装上阵,重头再来过了。再次谢谢大家
class Test
{
static void Main() {
string s = "Test";
string t = string.Copy(s);
Console.WriteLine(s == t);
Console.WriteLine((object)s == (object)t);
}
}
produces the outputTrueTrue
False
上面的代码实际相当于下面:string s = "Test";
string t = string.Copy(s);
object so = s;
object to = t;
Console.WriteLine(s == t);
Console.WriteLine(so == to);True
FalseTrue// “==”string类(.NET对string类如值类型处理),进行值类型的操作,就像比较int一样比较内存中的“堆栈”,由于两个都是"Test",显然为True
False //由于(object)s 和(object)t 为两次不同的装箱操作,并且string s 和 string t 在内存“堆”中两个副本的地址不同(但是 string s 和 string t 在“堆栈”中的原始值相同)。对于一般的类如object 类,== 表示比较引用,看是否指向内存(这里指内存中的“堆”,也就是存放副本的地方)中同一个地址。显然为False; //////////// 最最重要的一点是string.Copy()方法!! /////////////////string str1 = "Test";
string str2 = str; (str1 = "Test"也是一样)
//上面实际相当于引用,指向str1的内容,内存中只有一个"Test"
object s = str1;
object t = str2;
Console.WriteLine(s == t);结果为:True
但是下面用了Copy();string str1 = "Test";
string str2 = string.Copy(str1);//“深层”复制!内存中将有两个"Test"!
object s = str1;
object t = str2;
Console.WriteLine(s == t);如 bject o = (object) i;这样的显式执行装箱是毫无必要的
你的例子写的不错,注释的很好
真想把这个贴子改成示结的贴子.
不过,说实话 .Net 的内存管理同想象中的真是不一样.或者说,还不全是同一概念.