C#语言内置了3个引用类型,分别是string、object、dynamic。引用类型的变量又称为对象,可存储对实际数据的引用。实际数据是指存储在内存中某一段物理或逻辑上连续的空间上的数据,这段内存有一个首地址,而变量(或对象)保存了这个首地址(或指向首地址)。
哪些关键字可以声明引用类型?
- class
- interface
- 委托
string、object就是由class声明的引用类型。本节课我们将隆重介绍C#中引用类型的始祖——object。
object 类型在 .NET Framework 中是 Object 的别名。 在 C# 的统一类型系统中,所有类型(预定义类型、用户定义类型、引用类型和值类型)都是直接或间接从 Object 继承的。 可以将任何类型的值赋给 object 类型的变量。 将值类型的变量转换为对象的过程称为“装箱”。 将对象类型的变量转换为值类型的过程称为“取消装箱”或“拆箱”。
我们曾经在《类型、属性、方法的概念》一文中提到过继承,object就是C#中一切数据类型的始祖(基类)。所以可以将任意的数据赋值给object,它就像一个容器,可以容下任何数据。
下面我们将前面学过的数据类型尝试赋值给一个object对象,看看最终的效果。
static void Main(string[] args)
{
object a = true;
object b = byte.MaxValue;
object c = short.MaxValue;
object d = int.MaxValue;
object e = long.MaxValue;
object f = float.MaxValue;
object g = double.MaxValue;
object h = "hello,world";
object i = new object();
Console.WriteLine($"a={a}, type={a.GetType()}");
Console.WriteLine($"b={b}, type={b.GetType()}");
Console.WriteLine($"c={c}, type={c.GetType()}");
Console.WriteLine($"d={d}, type={d.GetType()}");
Console.WriteLine($"e={e}, type={e.GetType()}");
Console.WriteLine($"f={f}, type={f.GetType()}");
Console.WriteLine($"g={g}, type={g.GetType()}");
Console.WriteLine($"h={h}, type={h.GetType()}");
Console.WriteLine($"i={i}, type={i.GetType()}");
object j = new object();
Console.WriteLine($"j={j}, type={j.GetType()}");
j = a;
Console.WriteLine($"j={j}, type={j.GetType()}");
Console.ReadKey();
}
输出结果
a=True, type=System.Boolean
b=255, type=System.Byte
c=32767, type=System.Int16
d=2147483647, type=System.Int32
e=9223372036854775807, type=System.Int64
f=3.402823E+38, type=System.Single
g=1.79769313486232E+308, type=System.Double
h=hello,world, type=System.String
i=System.Object, type=System.Object
j=System.Object, type=System.Object
j=True, type=System.Boolean
结果分析
我们分别实例化了a-j这些object对象,并给他们赋值了不同的初始值,最后打印结果显示,这些对象的数据类型会随着真实的数据的类型而变化,特别是j,最初它就是System.Object类型,随着我们把a的值赋值给j,再观察j的类型,变成了System.Boolean。
将来我们学习了class自定义类型后,也可以将其赋值给一个object对象。
Object成员
在 Object 类中提供了 4 个常用的方法,即 Equals、GetHashCode、GetType 以及 ToString 方法。
1.Equals()方法
Equals 方法主要用于比较两个对象是否相等,如果相等则返回 True,否则返回 False。如果是引用类型的对象,则用于判断两个对象是否引用了同一个对象。实现上,object提供了两个Equals方法。一个是静态方法,一个是非静态方法。
public virtual bool Equals(object obj)
{
return RuntimeHelpers.Equals(this, obj);
}
[__DynamicallyInvokable]
public static bool Equals(object objA, object objB)
{
if (objA == objB)
{
return true;
}
if (objA == null || objB == null)
{
return false;
}
return objA.Equals(objB);
}
观察下面的例子
object o1 = new object();
object o2 = new object();
bool result1 = Equals(o1,o2);
Console.WriteLine($"o1 和 o2 比较结果: {result1}");
object o3 = o1;
bool result2 = Equals(o1,o3);
Console.WriteLine($"o1 和 o3 比较结果: {result2}");
bool result3 = o1.Equals( o3);
Console.WriteLine($"o1 和 o3 比较结果: {result3}");
输出结果
o1 和 o2 比较结果: False
o1 和 o3 比较结果: True
o1 和 o3 比较结果: True
2.GetHashCode()
GetHashCode 方法返回当前 System.Object 的哈希代码,每个对象的哈希值都是固定的。该方法不含有任何参数,并且不是静态方法,因此需要使用实例来调用该方法。由于该方法是在 Object 类中定义的,因此任何对象都可以直接调用该方法。
Console.WriteLine($"o1 的hash值: {o1.GetHashCode()}");
Console.WriteLine($"o2 的hash值: {o2.GetHashCode()}");
Console.WriteLine($"o3 的hash值: {o3.GetHashCode()}");
输出结果
o1 的hash值: 46104728
o2 的hash值: 12289376
o3 的hash值: 46104728
3.GetType()
用于获取当前实例的类型,返回值为 System.Type 类型。GetType 方法不含任何参数,是非静态方法。
Console.WriteLine($"o1 的Type值: {o1.GetType()}");
Console.WriteLine($"o2 的Type值: {o2.GetType()}");
Console.WriteLine($"o3 的Type值: {o3.GetType()}");
o1 的Type值: System.Object
o2 的Type值: System.Object
o3 的Type值: System.Object
由此可见,o1、o2、o3都是System.Object类型。
4.ToString()
返回一个对象实例的字符串,在默认情况下将返回类类型的限定名。C# 中几乎所有的类型都派生自 Object,所以如果当前类型没有重写 ToString() 方法的情况下,调用 ToString() 方法,默认返回当前类型的名称。任何类都可以重写 ToString 方法,返回自定义的字符串。
Console.WriteLine($"o1 的ToString()值: {o1.ToString()}");
Console.WriteLine($"o2 的ToString()值: {o2.ToString()}");
Console.WriteLine($"o3 的ToString()值: {o3.ToString()}");
o1 的ToString()值: System.Object
o2 的ToString()值: System.Object
o3 的ToString()值: System.Object
——重庆教主 2024年1月21日