【问题标题】:What is the purpose of casting into "object" type?转换为“对象”类型的目的是什么?
【发布时间】:2016-11-04 15:25:25
【问题描述】:

我在一个网站上找到了如下代码。

 string a = "xx";
 string b = "xx";
 string c = "x";
 string d = String.Intern(c + c);

 Console.WriteLine((object)a == (object)b); // True
 Console.WriteLine((object)a == (object)d); // True

这里,a,b,d 本身就是字符串的对象,再次转换成对象类型的目的是什么?

【问题讨论】:

  • 绝对没有。 System.String 继承自 System.Object
  • 无需投...
  • 该代码的作者想要调用operator==(object, object)(引用相等)而不是(就重载决议而言更合适)operator==(string, string)(值相等),因此进行了强制转换。运算符调用不是多态的,它们在编译时被解析。另一种方法是调用 object.ReferenceEquals() 而不进行强制转换。
  • 类型系统的颠覆。
  • 该网站缺少解释正在发生的事情的代码;也就是说,如果我们有string e = c + c;,那么e 和a 将不会使用“对象”版本比较相等,而是仅使用== 而不进行强制转换来比较相等。这是理解字符串实习的关键点:它改变了 reference 比较,同时保持 value 比较相同。

标签: c# .net string equality string-interning


【解决方案1】:

C# 编译器将在编译时尝试获取所有常量字符串。这称为字符串实习。所以在生成的代码a 和b 是references 对包含“xx”的same string。

您可以通过比较它们的引用来检查这一点(将它们转换为对象并进行相等检查或使用object.ReferenceEquals)。请记住,字符串的== 运算符比较它们的值而不是它们的引用。

另外要提的是.NET 中的strings are immutable。

string a = "xx";
string b = "x" + "x"; // String interning here
string c = string.Join("", new[] { "x", "x" }); // No interning here because it is evaluated at runtime

Console.WriteLine((object)a == (object)b); // True. Reference check
Console.WriteLine(a == b); // True. Value check

Console.WriteLine((object)a == c); //False. Reference check. Described below
Console.WriteLine(a == c); // True. Value check

那么为什么Console.WriteLine((object)a == c); 要做参考检查?因为编译器会在检查引用相等性的对象上选择== 运算符。


因此,在您的问题中强制转换为对象的全部目的是检查字符串实习是否有效。 假设在编译时没有实习发生。

 string a = "xx";
 string b = "xx";
 string c = "x";
 string d = String.Intern(c + c);

那么Console.WriteLine((object)a == (object)b); 将打印“False”,因为a 和b 是内存中两个不同字符串 的引用,两者看起来都像“ xx”。

【讨论】:

  • 手动构造字符串时需要显式实习吗? (如问题)
  • Operator == 对字符串进行值检查。 @卡尔
  • @dotctor 但是在这种情况下,根据您的解释,这是否意味着a的引用等于引用b,改变b的值应该导致改变a的值? String 是一个引用类型,它引用了 Heap 中的一个对象?
  • 字符串在 .NET 中是不可变的。所以你不能改变它们的价值。 @传奇
  • 编译器在编译时使用字符串实习过程来完成。 a 也引用了与 d 相同的字符串,因为 d 是使用实习过程生成的。在运行时,使用string.Intern 检索对“xx”的引用并分配给d,因此a 和d 引用相同的东西。
【解决方案2】:

对所提供答案的补充: string (C# Reference)

System.String 类是不可变的引用类型 .NET 框架类库。此类创建一个新字符串 用于任何字符串操作操作的内部对象。的内容 这种类型的对象不会改变,尽管语法使它 看起来好像内容可以更改。此外,字符串用作 哈希表键用于计算哈希值以避免风险 破坏哈希数据结构。

示例:

string a = "hello";
string b = "h";

// Append to contents of 'b'
b += "ello";
// When you set the variable's b value to "hello", 
// this would result in changing the pointer
// to the object in the HEAP the variable "a" is already pointing to
// Result would be: (reference of a == reference of b) --> TRUE
// b = "hello"; 

Console.WriteLine(a == b);                       // value comparison
Console.WriteLine((object)a == (object)b);       // reference comparison
Console.WriteLine (object.ReferenceEquals(a,b)); // reference comparison without casting

结果:

True
False
False

说明:

这将创建一个新对象:

string a = "hello";

这将创建另一个对象:

string b = "h"; 

这将创建另一个对象:

b += "ello";

下面将创建一个对现有对象的引用,更准确地说,它将指向变量“a”指向的同一个对象→“hello”。

string c = "hello"; 
Console.WriteLine (object.ReferenceEquals(a,c)); // --> TRUE

字符串是不可变的--字符串对象的内容不能 创建对象后更改,尽管语法使其 看起来好像你可以做到这一点。例如,当您编写此代码时, 编译器实际上创建了一个新的字符串对象来保存新的 字符序列,并将新对象分配给 b。这 然后字符串 "h" 就可以进行垃圾回收了。

【讨论】:

  • 您不应该提及堆或堆栈,因为这些是 .NET 运行时的实现细节,并且在不同版本之间可能会有所不同。 Heap and Stack
  • 我指的是“微软在 CLR 上的 C# 实现”。这只是对您的答案的补充,以使其更容易理解;-)
【解决方案3】:

C# 使用== 标记来表示三个不同的运算符:一个可重载的相等检查运算符(如果存在针对所讨论的确切类型的重载,则可用于类类型或值类型),一个不可重载的引用标识检查运算符(要求两个操作数都是类引用,并且要求类型不能互斥)和空值检查运算符(可用于任何类类型、可为空值类型或可能是上述之一的泛型)。虽然大多数形式的重载是在 .NET 语言中以统一的方式定义的,但对所有三种相等性使用一个运算符却不是。其他语言如 VB.NET 对第一种形式使用不同的标记(例如,在 VB.NET 中,表达式 (x = y) 如果定义了一个则使用相等测试重载,否则生成语法错误;(x Is y) 测试是否x 和 y 标识同一个对象实例,而不考虑是否存在重载的相等运算符)。

转换为Object 的目的是确保== 标记被解释为表示引用身份检查运算符而不是可重载的相等运算符;仅因为 C 如何实现 == 运算符,才需要此类转换,而在 VB.NET 等其他语言中则不需要。

【讨论】:

    【解决方案4】:

    用代码注释

    因此,如果在运行时将值“xx”全部设置为相同的“xx”值,那么您将得到不同的 false 结果,因为编译器没有机会在运行时进行优化,即使它是两种情况下的代码和输入值相同,预编译与运行时的结果不同。

    private void button1_Click(object sender, EventArgs e)
    {
        string a = "xx";
        string b = "xx";
        string c = "x";
        string d = String.Intern(c + c);
    
        Console.WriteLine((object)a == (object)b); // True
        Console.WriteLine((object)a == (object)d); // True
    }
    
    private void button2_Click(object sender, EventArgs e)
    {
        string a = textBox1.Text; //type in xx at runtime
        string b = textBox2.Text; //type in xx at runtime
        string c = textBox3.Text; //type in just "x" at runtime
        string d = String.Intern(c + c);
    
        Console.WriteLine((object)a == (object)b); // False with runtime values that have the same value
        Console.WriteLine((object)a == (object)d); // False 
        Console.WriteLine(a == d); // True - the Equals Operator of the string works as expected still 
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-17
      • 1970-01-01
      • 2016-04-02
      • 2022-01-25
      • 1970-01-01
      • 2014-03-21
      • 2011-02-10
      • 1970-01-01
      相关资源
      最近更新 更多