比较C#和Ruby在比较对象的平等性
C#和Ruby在比较对象的平等性方面有着相似的语法。两者都使用运算符equals(==)和至少一种方法来比较。Ruby使用equal?和eql?,C#使用Equals。另外,两者都支持重写equals (==)操作符,以便在需要时提供不同的逻辑。这些方法的名称不同,但它们的工作原理基本相同。
理解这两种语言的区别其实很简单。如果你已经知道了引用类型和数值类型之间的区别,那么你就基本掌握了。
红宝石
方法等于?
用来测试两个对象中的引用相等的方法。比如说。
#!/usr/bin/env ruby
a = 0
b = 0.0
c = b
d = e = 0
# "false" pointer c points to b, and b and a
# are different types.w
puts "c.equal?(a) #{c.equal?(a)}"
# "false" b and a are different types
puts "b.equal?(a) #{b.equal?(a)}"
# "true" Same type, same value.
puts "d.equal?(e) #{d.equal?(e)}"</pre>
方法eql?
的同义词,不是严格的类型转换。注意哈希类使用这个方法来创建哈希,所以如果两个值是相同的,哈希方法应该返回相同的值。
#!/usr/bin/env ruby
a = 0
b = 0.0
c = b
d = e = 0
# "false" Pointer c points to b, and b and a are different types
puts "c.eql?(a) #{c.eql?(a)}"
# "false" Different types
puts "b.eql?(a) #{b.eql?(a)}"
# "true" Same type, same value.
puts "d.eql?(e) #{d.eql?(e)}"
操作符等价(==)。
默认情况下,在Object类中,它是equal?的同义词。测试引用平等。
#!/usr/bin/env ruby
a = 0
b = 0.0
c = b
d = e = 0
# "true" Even when pointer c points to b, and b and a
# are different types, the value is the same
puts "c == a #{c == a}"
# "true" Type is casted to allow comparing them
puts "b == a #{b == a}"
# "true" Same type, same value.
puts "d == e #{d == e}"
C#
在解释平等选项之前,请注意Ruby和C#之间的一个重要区别。
首先,Ruby是一种动态类型的语言。在声明变量时,没有变量类型的含义,所有的变量都可以根据情况用来识别不同类型的实例。例如,我们可以定义一个变量x充当字符串,然后用同一个变量x充当整数,这并不意味着我们将字符串转换为整数,这意味着我们将同一个指针(变量x)用于两种不同的类型,字符串和整数,指向内存中两个不同的地址。比如说。
#!/usr/bin/env ruby
a = "I'm string"
# Output: "a Value: 'I'm string' Class: 'String'"
puts "a Value: '#{a}' Class: '#{a.class}'"
# Output: "a Value: '10.0' Class: 'Float'"
a = 10.0
puts "a Value: '#{a}' Class: '#{a.class}'"</pre>
C#是一种静态类型的语言,所有的变量都必须在实例化一个对象之前表明其类型。例如,当声明一个字符串类型的变量x时,你将能够创建一个字符串的实例,只是,没有办法在同一范围内将x"重用 "为一个整数。试着编译下面的例子,它将会失败。
public class RubyAndCSharp {
public static void Main (string []args) {
string x = "I'm string";
System.Console.WriteLine ("a Value: '{0}' Class: '{1}'", x, x.GetType ());
x = 10.0; // It will fail here: "error CS0029: Cannot implicitly convert type `double' to `string'"
System.Console.WriteLine ("a Value: '{0}' Class: '{1}'", x, x.GetType ());
}
}
第二,内存管理。两种语言都是自动管理内存:默认情况下,所有的内存都是自动创建和释放的,不需要显式释放或分配内存,除非程序员想这样做。然而,在C#中,类型之间有一个 "区别"。有两个类型类别。值类型和引用类型。与内存使用有关的区别是它们的工作方式和它们使用的内存地址。声明值类型会自动分配内存,声明引用类型会声明一个指针,当变量所指向的对象被实例化时,内存会被分配。值类型是在堆栈中分配的,而引用类型是在堆中分配的。
这个区别真的很重要。比较两个不同 "类别 "的objects 实例,一个是值类型,一个是引用类型,是行不通的,只会失败。就像比较一个苹果和一个桔子。就像比较一个存储在堆栈中的值和一个存储在堆中的值。我们不能在不写任何额外代码的情况下比较它们。
而这个额外的代码意味着使用基类object 作为不同类型的指针,因为这两种类型,值类型和引用类型,都是对象的子类,以这种或那种方式。让我们试着编译下面这个例子。
public class RubyAndCSharp {
public static void Main (string []args) {
object x = "I'm string";
// Output: "a Value: 'I'm string' Class: 'System.String'"
System.Console.WriteLine ("a Value: '{0}' Class: '{1}'", x, x.GetType ());
x = 10.0;
// Output: "a Value: '10' Class: 'System.Double'"
System.Console.WriteLine ("a Value: '{0}' Class: '{1}'", x, x.GetType ());
}
}
在这个简短(或漫长?)的解释之后,我们准备看看谈论方法。
方法Object.Equals()
用来测试引用类型中的引用相等和值类型中的位相等。比如说。
public class RubyAndCSharp {
class MyClass {
public string Name { get; set; }
public override string ToString () { return Name; }
}
public static void Main (string []args) {
// object.Equals in Reference Types uses address memory
MyClass myClass0 = new MyClass () { Name = "test" };
MyClass myClass1 = myClass0;
System.Console.WriteLine ("object.Equals('{0}','{1}') = {2}", myClass0, myClass1, object.Equals (myClass0, myClass1));
// Let's try again. This will return false. myClass1 and myClass2 are different instances
myClass1 = new MyClass () { Name = "test" };
System.Console.WriteLine ("object.Equals('{0}','{1}') = {2}", myClass0, myClass1, object.Equals (myClass0, myClass1));
// It doesn't matter myInt0 and myInt1 are different variables, equality will be true.
int myInt0 = 1;
int myInt1 = 1;
System.Console.WriteLine ("object.Equals('{0}','{1}') = {2}", myInt0, myInt1, object.Equals (myInt0, myInt1));
}
}
操作符等价(==)
基本上是object.Equals的同义词,适用相同的规则。
public class RubyAndCSharp {
class MyClass {
public string Name { get; set; }
public override string ToString () { return Name; }
}
public static void Main (string []args) {
// == in Reference Types uses address memory
MyClass myClass0 = new MyClass () { Name = "test" };
MyClass myClass1 = myClass0;
System.Console.WriteLine ("object.Equals('{0}','{1}') = {2}", myClass0, myClass1, myClass0 == myClass1);
// Let's try again. This will return false. myClass1 and myClass2 are different instances
myClass1 = new MyClass () { Name = "test" };
System.Console.WriteLine ("object.Equals('{0}','{1}') = {2}", myClass0, myClass1, myClass0 == myClass1);
// It doesn't matter myInt0 and myInt1 are different variables
int myInt0 = 1;
int myInt1 = 1;
System.Console.WriteLine ("object.Equals('{0}','{1}') = {2}", myInt0, myInt1, myInt0 == myInt1);
}
}
操作符Object.ReferenceEquals()
很直接,测试引用。
public class RubyAndCSharp {
class MyClass {
public string Name { get; set; }
public override string ToString () { return Name; }
}
public static void Main (string []args) {
// Object.ReferenceEquals in Reference Types uses address memory
MyClass myClass0 = new MyClass () { Name = "test" };
MyClass myClass1 = myClass0;
System.Console.WriteLine ("object.Equals('{0}','{1}') = {2}", myClass0, myClass1, System.Object.ReferenceEquals (myClass0, myClass1));
// Let's try again. This will return false. myClass1 and myClass2 are different instances
myClass1 = new MyClass () { Name = "test" };
System.Console.WriteLine ("object.Equals('{0}','{1}') = {2}", myClass0, myClass1, System.Object.ReferenceEquals (myClass0, myClass1));
// This will also return false.
int myInt0 = 1;
int myInt1 = 1;
System.Console.WriteLine ("object.Equals('{0}','{1}') = {2}", myInt0, myInt1, System.Object.ReferenceEquals (myInt0, myInt1));
}
}
科罗芬
有时你必须使用一个对象引用来引用两种类型,值和引用,如果你打算比较它们的值,你必须使用静态方法object.Equals(a,b)。使用运算符equals(==)将总是返回false,因为有boxing/unboxing的问题。
public class RubyAndCSharp {
public static void Main (string []args) {
string str0 = "hola";
string str1 = "hola";
object obj0 = str0;
object obj1 = str1;
System.Console.WriteLine ("Equals: {0}, Using ==: {1}, object.Equals {2}",
obj0.Equals (obj1), // True
obj0 == obj1, // True
object.Equals (obj0, obj1)); // True
bool bool0 = true;
bool bool1 = true;
obj0 = bool0;
obj1 = bool1;
System.Console.WriteLine ("Equals: {0}, ==: {1}, object.Equals {2}",
obj0.Equals (obj1), // True
obj0 == obj1, // False
object.Equals (obj0, obj1)); // True
}
}