日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

C#Object类型

發(fā)布時(shí)間:2023/12/29 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#Object类型 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在C#中,Object類型是所有類型的根,大家平常開(kāi)發(fā)中都要跟它打交道,但不見(jiàn)得對(duì)它里面的每個(gè)方法都知根知底,下面對(duì)它里面的每個(gè)方法都進(jìn)行仔細(xì)的總結(jié)。
概述:
構(gòu)造函數(shù)
Equals函數(shù)
Finalize函數(shù)
GetHashCode函數(shù)
GetType()函數(shù)
ReferenceEquals函數(shù)
MemberWiseClone()函數(shù)
ToString()函數(shù)
Object類型中一共有8個(gè)方法,重載的方法沒(méi)有算進(jìn)來(lái)。下面一一來(lái)看看這些方法。
1、構(gòu)造函數(shù)
函數(shù)簽名:public Object()
作用:這個(gè)就不用多說(shuō)了
注意點(diǎn):直接使用new Object()可以用來(lái)創(chuàng)建對(duì)象;如果非Object類型,則在該類型的構(gòu)造函數(shù)被調(diào)用時(shí),該函數(shù)自動(dòng)被調(diào)用。
2、Equals函數(shù),該方法有重載函數(shù)
函數(shù)簽名:public virtual bool Equals(Object obj)
public static bool Equals(Object objA,Object objB)
先來(lái)看看public virtual bool Equals(Object obj),從簽名里就可以看出來(lái),這個(gè)方法是用來(lái)開(kāi)放給繼承類去根據(jù)實(shí)際情況重寫的。
注意點(diǎn):
1)默認(rèn)情況下,對(duì)于引用類型,該方法對(duì)比的時(shí)引用的地址,對(duì)于值類型,對(duì)比的是值的二進(jìn)制描述是否相同。100.0與100雖然都是100,但是它們的二進(jìn)制分布是不一樣的。
2)不管是引用類型還是值類型,重寫該方法的主要目的都是實(shí)現(xiàn)根據(jù)值來(lái)判斷對(duì)象是否相等。
3)該方法本身只支持原子類型的比較以及簡(jiǎn)單對(duì)象的比較,如果是自定義復(fù)雜的類型,則有必要重寫該方法。
4)重寫該方法時(shí),應(yīng)滿足一些規(guī)則。
首先x.Equals(x)應(yīng)該返回true;
x.Equals(y)的結(jié)果應(yīng)該與y.Equals(x)相同;
x.Equals(y)返回true,如果x和y都是Nan;
如果x.Equals(y) && y.Equals(z),則x.Equals(z)應(yīng)該返回true;
x.Equals(null)都返回false;
5)在重寫Equals()方法時(shí),不應(yīng)該拋出異常;
6)實(shí)現(xiàn)IComparable接口的話,一定記得重寫Equals方法;
7)如果重寫了Equals(),則一般情況也必須重寫GetHashCode(),不然如果把該類型的對(duì)方放在hashtable結(jié)構(gòu)上的話可能產(chǎn)生問(wèn)題;
8)如果對(duì)==進(jìn)行了操作符重載,則記得一定重寫Equals();按照這樣的設(shè)計(jì)方法,類型代碼在調(diào)用Equals時(shí)的運(yùn)行結(jié)果,能夠跟應(yīng)用程序調(diào)用==時(shí)的結(jié)果保持一致。
看完了public virtual bool Equals(Object obj),我們接著來(lái)看看它的重載方法public static bool Equals(Object objA,Object objB)
該方法返回true的條件:
1)objA和objB是同一個(gè)實(shí)例
2)objA和objB都是null
3)objA.Equas(objB)返回true
注意上面三個(gè)條件是||的關(guān)系
對(duì)比這兩個(gè)Equals方法,還是很容易對(duì)比出不同點(diǎn)的。
3、Finalize函數(shù)
函數(shù)簽名:protected virtual void Finalize()
作用:允許對(duì)象在垃圾回收回收該對(duì)象之前嘗試釋放資源并執(zhí)行其它清理操作。
注意點(diǎn):
Finalize 是受保護(hù)的,因此只能通過(guò)此類或派生類訪問(wèn)它。
對(duì)象變?yōu)椴豢稍L問(wèn)后將自動(dòng)調(diào)用此方法,除非已通過(guò) SuppressFinalize 調(diào)用使對(duì)象免除了終結(jié)。在應(yīng)用程序域的關(guān)閉過(guò)程中,對(duì)沒(méi)有免除終結(jié)的對(duì)象將自動(dòng)調(diào)用 Finalize,即使那些對(duì)象仍是可訪問(wèn)的。對(duì)于給定的實(shí)例僅自動(dòng)調(diào)用 Finalize 一次,除非使用 ReRegisterForFinalize 這類機(jī)制重新注冊(cè)該對(duì)象并且后面沒(méi)有調(diào)用 GC.SuppressFinalize。
派生類型中的每個(gè) Finalize 實(shí)現(xiàn)都必須調(diào)用其基類型的 Finalize 實(shí)現(xiàn)。這是唯一一種允許應(yīng)用程序代碼調(diào)用 Finalize 的情況。
Finalize 操作具有下列限制:
垃圾回收過(guò)程中執(zhí)行終結(jié)器的準(zhǔn)確時(shí)間是不確定的。不保證資源在任何特定的時(shí)間都能釋放,除非調(diào)用 Close 方法或 Dispose 方法。
即使一個(gè)對(duì)象引用另一個(gè)對(duì)象,也不能保證兩個(gè)對(duì)象的終結(jié)器以任何特定的順序運(yùn)行。即,如果對(duì)象 A 具有對(duì)對(duì)象 B 的引用,并且兩者都有終結(jié)器,則當(dāng)對(duì)象 A 的終結(jié)器啟動(dòng)時(shí),對(duì)象 B 可能已經(jīng)終結(jié)了。
運(yùn)行終結(jié)器的線程是未指定的。
在下面的異常情況下,Finalize 方法可能不會(huì)運(yùn)行完成或可能根本不運(yùn)行:
另一個(gè)終結(jié)器無(wú)限期地阻止(進(jìn)入無(wú)限循環(huán),試圖獲取永遠(yuǎn)無(wú)法獲取的鎖,諸如此類)。由于運(yùn)行時(shí)試圖運(yùn)行終結(jié)器來(lái)完成,所以如果一個(gè)終結(jié)器無(wú)限期地阻止,則可能不會(huì)調(diào)用其他終結(jié)器。
進(jìn)程終止,但不給運(yùn)行時(shí)提供清理的機(jī)會(huì)。在這種情況下,運(yùn)行時(shí)的第一個(gè)進(jìn)程終止通知是 DLL_PROCESS_DETACH 通知。
在關(guān)閉過(guò)程中,只有當(dāng)可終結(jié)對(duì)象的數(shù)目繼續(xù)減少時(shí),運(yùn)行時(shí)才繼續(xù) Finalize 對(duì)象。
如果 Finalize 或 Finalize 的重寫引發(fā)異常,并且運(yùn)行庫(kù)并非寄宿在重寫默認(rèn)策略的應(yīng)用程序中,則運(yùn)行庫(kù)將終止進(jìn)程,并且不執(zhí)行任何活動(dòng)的 try-finally 塊或終結(jié)器。如果終結(jié)器無(wú)法釋放或銷毀資源,此行為可以確保進(jìn)程完整性。
對(duì)實(shí)現(xiàn)者的說(shuō)明:
默認(rèn)情況下,Object..::.Finalize 不執(zhí)行任何操作。只有在必要時(shí)才必須由派生類重寫它,因?yàn)槿绻仨氝\(yùn)行 Finalize 操作,垃圾回收過(guò)程中的回收往往需要長(zhǎng)得多的時(shí)間。
如果 Object 保存了對(duì)任何資源的引用,則 Finalize 必須由派生類重寫,以便在垃圾回收過(guò)程中,在放棄 Object 之前釋放這些資源。
當(dāng)類型使用文件句柄或數(shù)據(jù)庫(kù)連接這類在回收使用托管對(duì)象時(shí)必須釋放的非托管資源時(shí),該類型必須實(shí)現(xiàn) Finalize。有關(guān)輔助和具有更多控制的資源處置方式,請(qǐng)參見(jiàn) IDisposable 接口。
Finalize 可以采取任何操作,包括在垃圾回收過(guò)程中清理了對(duì)象后使對(duì)象復(fù)活(即,使對(duì)象再次可訪問(wèn))。但是,對(duì)象只能復(fù)活一次;在垃圾回收過(guò)程中,不能對(duì)復(fù)活對(duì)象調(diào)用 Finalize。
析構(gòu)函數(shù)是執(zhí)行清理操作的 C# 機(jī)制。析構(gòu)函數(shù)提供了適當(dāng)?shù)谋Wo(hù)措施,如自動(dòng)調(diào)用基類型的析構(gòu)函數(shù)。
4、GetHashCode函數(shù)
函數(shù)簽名:public virtual int GetHashCode()
作用:用作特定類型的哈希函數(shù)。
注意點(diǎn):
GetHashCode 方法適用于哈希算法和諸如哈希表之類的數(shù)據(jù)結(jié)構(gòu)。
GetHashCode 方法的默認(rèn)實(shí)現(xiàn)不保證針對(duì)不同的對(duì)象返回唯一值。而且,.NET Framework 不保證 GetHashCode 方法的默認(rèn)實(shí)現(xiàn)以及它所返回的值在不同版本的 .NET Framework 中是相同的。因此,在進(jìn)行哈希運(yùn)算時(shí),該方法的默認(rèn)實(shí)現(xiàn)不得用作唯一對(duì)象標(biāo)識(shí)符。
GetHashCode 方法可以由派生類型重寫。值類型必須重寫此方法,以提供適合該類型的哈希函數(shù)和在哈希表中提供有用的分布。為了獲得最佳結(jié)果,哈希代碼必須基于實(shí)例字段或?qū)傩?#xff08;而非靜態(tài)字段或?qū)傩?#xff09;的值。
用作 Hashtable 對(duì)象中鍵的對(duì)象還必須重寫 GetHashCode 方法,因?yàn)檫@些對(duì)象必須生成其各自的哈希代碼。如果用作鍵的對(duì)象不提供 GetHashCode 的有用實(shí)現(xiàn),您可以在構(gòu)造 Hashtable 對(duì)象時(shí)指定哈希代碼提供程序。在 .NET Framework 2.0 版之前,哈希代碼提供程序是基于 System.Collections..::.IHashCodeProvider 接口的。從 2.0 版開(kāi)始,哈希代碼提供程序基于 System.Collections..::.IEqualityComparer 接口。
對(duì)實(shí)現(xiàn)者的說(shuō)明:
哈希函數(shù)用于快速生成一個(gè)與對(duì)象的值相對(duì)應(yīng)的數(shù)字(哈希代碼)。哈希函數(shù)通常是特定于每個(gè) Type 的,而且,必須至少使用一個(gè)實(shí)例字段作為輸入。
哈希函數(shù)必須具有以下特點(diǎn):
如果兩個(gè)對(duì)象的比較結(jié)果相等,則每個(gè)對(duì)象的 GetHashCode 方法都必須返回同一個(gè)值。但是,如果兩個(gè)對(duì)象的比較結(jié)果不相等,則這兩個(gè)對(duì)象的 GetHashCode 方法不一定返回不同的值。
一個(gè)對(duì)象的 GetHashCode 方法必須總是返回同一個(gè)哈希代碼,但前提是沒(méi)有修改過(guò)對(duì)象狀態(tài),對(duì)象狀態(tài)用來(lái)確定對(duì)象的 Equals 方法的返回值。請(qǐng)注意,這僅適用于應(yīng)用程序的當(dāng)前執(zhí)行,再次運(yùn)行該應(yīng)用程序時(shí)可能會(huì)返回另一個(gè)哈希代碼。
為了獲得最佳性能,哈希函數(shù)必須為所有輸入生成隨機(jī)分布。
例如,String 類提供的 GetHashCode 方法的實(shí)現(xiàn)為相同的字符串值返回相同的哈希代碼。因此,如果兩個(gè) String 對(duì)象表示相同的字符串值,則它們返回相同的哈希代碼。另外,該方法使用字符串中的所有字符生成相當(dāng)隨機(jī)的分布式輸出,即使當(dāng)輸入集中在某些范圍內(nèi)時(shí)(例如,許多用戶可能有只包含低位 128 個(gè) ASCII 字符的字符串,即使字符串可以包含 65,535 個(gè) Unicode 字符中的任何字符)。
對(duì)于 Object 的派生類,當(dāng)且僅當(dāng)此派生類將值相等性定義為引用相等并且類型不是值類型時(shí),GetHashCode 方法才可以委托給 Object..::.GetHashCode 實(shí)現(xiàn)。
在類上提供好的哈希函數(shù)可以顯著影響將這些對(duì)象添加到哈希表的性能。在具有好的哈希函數(shù)實(shí)現(xiàn)的哈希表中,搜索元素所用的時(shí)間是固定的(例如運(yùn)算復(fù)雜度為 O(1) 的運(yùn)算)。而在具有不好的哈希函數(shù)實(shí)現(xiàn)的哈希表中,搜索性能取決于哈希表中的項(xiàng)數(shù)(例如運(yùn)算復(fù)雜度為 O(n) 的運(yùn)算,其中的 n 是哈希表中的項(xiàng)數(shù))。哈希函數(shù)的計(jì)算成本也必須不高。
GetHashCode 方法的實(shí)現(xiàn)必須不會(huì)導(dǎo)致循環(huán)引用。例如,如果 ClassA.GetHashCode 調(diào)用 ClassB.GetHashCode,ClassB.GetHashCode 必須不直接或間接調(diào)用 ClassA.GetHashCode。
GetHashCode 方法的實(shí)現(xiàn)必須不引發(fā)異常。
重寫 GetHashCode 的派生類還必須重寫 Equals,以保證被視為相等的兩個(gè)對(duì)象具有相同的哈希代碼;否則,Hashtable 類型可能無(wú)法正常工作。
示例
在某些情況下,GetHashCode 方法的實(shí)現(xiàn)只返回整數(shù)值。下面的代碼示例闡釋了返回整數(shù)值的 GetHashCode 的實(shí)現(xiàn)。
using System;
public struct Int32 {
public int value;
//other methods…
public override int GetHashCode()
{
return value;
}
}
一個(gè)類型常具有多個(gè)可以參與生成哈希代碼的數(shù)據(jù)字段。生成哈希代碼的一種方法是使用 XOR (eXclusive OR) 運(yùn)算合并這些字段,如下面的代碼示例所示。
using System;
public struct Point {
public int x;
public int y;
//other methods
public override int GetHashCode() {
return x ^ y;
}
}
下面的代碼示例闡釋了另一種情況:使用 XOR (eXclusive OR) 合并該類型的字段以生成哈希代碼。注意,在該代碼示例中,字段表示用戶定義的類型,每個(gè)類型都實(shí)現(xiàn) GetHashCode 和 Equals。
using System;
public class SomeType {
public override int GetHashCode() {
return 0;
}
}
public class AnotherType {
public override int GetHashCode() {
return 1;
}
}
public class LastType {
public override int GetHashCode() {
return 2;
}
}
public class MyClass {
SomeType a = new SomeType();
AnotherType b = new AnotherType();
LastType c = new LastType();
public override int GetHashCode () {
return a.GetHashCode() ^ b.GetHashCode() ^ c.GetHashCode();
}
}
如果派生類的數(shù)據(jù)成員比 Int32 大,則可以使用 XOR (eXclusive OR) 運(yùn)算合并該值的高序位和低序位,如下面的代碼示例所示。
using System;
public struct Int64 {
public long value;
//other methods…
public override int GetHashCode() {
return ((int)value ^ (int)(value >> 32));
}
}
5、GetType()函數(shù)
函數(shù)簽名:public Type GetType()
作用:獲取當(dāng)前實(shí)例的確切運(yùn)行時(shí)類型。
注意點(diǎn):
對(duì)于具有相同運(yùn)行時(shí)類型的兩個(gè)對(duì)象 x 和 y,雖然Object.ReferenceEquals(x,y)返回的是false,但是 Object.ReferenceEquals(x.GetType(),y.GetType()) 返回 true。
Type 對(duì)象公開(kāi)與當(dāng)前 Object 的類關(guān)聯(lián)的元數(shù)據(jù)。
下面的代碼示例說(shuō)明 GetType 返回當(dāng)前實(shí)例的運(yùn)行時(shí)類型。
using System;
public class MyBaseClass: Object {
}
public class MyDerivedClass: MyBaseClass {
}
public class Test {
public static void Main() {
MyBaseClass myBase = new MyBaseClass();
MyDerivedClass myDerived = new MyDerivedClass();
object o = myDerived;
MyBaseClass b = myDerived;
Console.WriteLine(“mybase: Type is {0}”, myBase.GetType());
Console.WriteLine(“myDerived: Type is {0}”, myDerived.GetType());
Console.WriteLine(“object o = myDerived: Type is {0}”, o.GetType());
Console.WriteLine(“MyBaseClass b = myDerived: Type is {0}”, b.GetType());
}
}
6、ReferenceEquals函數(shù)
函數(shù)原型:public static bool ReferenceEquals( Object objA,Object objB )
作用:判斷兩個(gè)指定的對(duì)象實(shí)例是否是同一個(gè)實(shí)例。從描述也可以看出來(lái),如果參數(shù)是值類型,則會(huì)裝箱,比較的是裝箱后的對(duì)象實(shí)例。
注意:
如果 objA 是與 objB 是相同的實(shí)例,或者如果二者都為空引用,則為 true;否則為 false。
下面的代碼示例使用 ReferenceEquals 確定兩個(gè)對(duì)象是否是相同的實(shí)例。
using System;
class MyClass {
static void Main() {
object o = null;
object p = null;
object q = new Object();
Console.WriteLine(Object.ReferenceEquals(o, p));
p = q;
Console.WriteLine(Object.ReferenceEquals(p, q));
Console.WriteLine(Object.ReferenceEquals(o, p));
}
}
7、MemberWiseClone()函數(shù)
函數(shù)簽名:protected Object MemberWiseClone()
作用:創(chuàng)建當(dāng)前 Object 的淺表副本。
注意:
MemberwiseClone 方法創(chuàng)建一個(gè)淺表副本,方法是創(chuàng)建一個(gè)新對(duì)象,然后將當(dāng)前對(duì)象的非靜態(tài)字段復(fù)制到該新對(duì)象。如果字段是值類型的,則對(duì)該字段執(zhí)行逐位復(fù)制。如果字段是引用類型,則復(fù)制引用但不復(fù)制引用的對(duì)象;因此,原始對(duì)象及其復(fù)本引用同一對(duì)象。非靜態(tài)字段屬于整個(gè)類,不管是深拷貝,還是淺拷貝,都是不需要處理的。并且需要注意該方法是protected的,即只有在類本身內(nèi)部,或者它的繼承者內(nèi)部才能夠調(diào)用它。
例如,考慮一個(gè)名為 X 的對(duì)象,該對(duì)象引用對(duì)象 A 和 B。對(duì)象 B 又引用對(duì)象 C。X 的淺表副本創(chuàng)建一個(gè)新對(duì)象 X2,該對(duì)象也引用對(duì)象 A 和 B。與此相對(duì)照,X 的深層副本創(chuàng)建一個(gè)新對(duì)象 X2,該對(duì)象引用新對(duì)象 A2 和 B2,它們分別是 A 和 B 的副本。B2 又引用新對(duì)象 C2,C2 是 C 的副本。使用實(shí)現(xiàn) ICloneable 接口的類執(zhí)行對(duì)象的淺表或深層復(fù)制。
下面的代碼示例說(shuō)明如何使用 MemberwiseClone 復(fù)制類的實(shí)例。
using System;
class MyBaseClass {
public static string CompanyName = “My Company”;
public int age;
public string name;
}
class MyDerivedClass: MyBaseClass {
static void Main() {
// Creates an instance of MyDerivedClass and assign values to its fields.
MyDerivedClass m1 = new MyDerivedClass();
m1.age = 42;
m1.name = “Sam”;
// Performs a shallow copy of m1 and assign it to m2.
MyDerivedClass m2 = (MyDerivedClass) m1.MemberwiseClone();
}
}
8、ToString()函數(shù)
函數(shù)簽名:public virtual string ToString()
作用:返回一個(gè)代表當(dāng)前對(duì)象的字符串
注意:默認(rèn)情況下返回的是該對(duì)象所屬類型的全名稱。繼承類可以重寫該方法,以便自定義顯示輸出內(nèi)容,如果繼承類需要控制更多的格式化輸出,則需要實(shí)現(xiàn)IFormattable接口。
下面的代碼演示了如何重寫ToString(),以及如何實(shí)現(xiàn)IFormattable接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace IFormattablePractise
{
public class Point : IFormattable
{
int x;
int y;
public Point(int x , int y)
{
this.x = x;
this.y = y;
}
public override string ToString()
{
return ToString(null, null);
}

region IFormattable Members

public string ToString(string format, IFormatProvider formatProvider)
{
// If no format is passed, display like this: (x, y).
if (format == null) return String.Format(“({0}, {1})”, x, y);
// For “x” formatting, return just the x value as a string
if (format == “x”) return x.ToString();
// For “y” formatting, return just the y value as a string
if (format == “y”) return y.ToString();
// For any unrecognized format, throw an exception.
throw new FormatException(String.Format(“Invalid format string: ‘{0}’.”, format));
}

endregion

}
class Program
{
static void Main(string[] args)
{
// Create the object.
Point p = new Point(5, 98);
// Test ToString with no formatting.
Console.WriteLine(“This is my point: ” + p.ToString());
// Use custom formatting style “x”
Console.WriteLine(“The point’s x value is {0:x}”, p);
// Use custom formatting style “y”
Console.WriteLine(“The point’s y value is {0:y}”, p);
Console.WriteLine(“my custom point value is ({0:x}:{1:y})”,p,p);
try
{
// Use an invalid format; FormatException should be thrown here.
Console.WriteLine(“Invalid way to format a point: {0:XYZ}”, p);
}
catch (FormatException e)
{
Console.WriteLine(“The last line could not be displayed: {0}”, e.Message);
}
Console.ReadLine();
}
}
}

轉(zhuǎn)自:http://blog.csdn.net/wnln25/article/details/6678357
C#中的object類深入理解
C#中所有的類都直接或間接繼承自System.Object類,這使得C#中的類得以單根繼承。如果我們沒(méi)有明確指定繼承類,編譯器缺省認(rèn)為該類繼承自System.Object類。System.Object類也可用小寫的object關(guān)鍵字表示,兩者完全等同。自然C#中所有的類都繼承了System.Object類的公共接口,剖析它們對(duì)我們理解并掌握C#中類的行為非常重要。下面是僅用接口形式表示的System.Object類:

namespace System
{
public class Object
{
public static bool Equals(object objA,object objB){}
public static bool ReferenceEquals(object objA,object objB){}

public Object(){}public virtual bool Equals(object obj){}public virtual int GetHashCode(){}public Type GetType(){}public virtual string ToString(){}protected virtual void Finalize(){}protected object MemberwiseClone(){} }

我們先看object的兩個(gè)靜態(tài)方法Equals(object objA,object objB),ReferenceEquals(object objA,object objB)和一個(gè)實(shí)例方法Equals(object obj)。在我們闡述這兩個(gè)方法之前我們首先要清楚面向?qū)ο缶幊虄蓚€(gè)重要的相等概念:值相等和引用相等。值相等的意思是它們的數(shù)據(jù)成員按內(nèi)存位分別相等。引用相等則是指它們指向同一個(gè)內(nèi)存地址,或者說(shuō)它們的對(duì)象句柄相等。引用相等必然推出值相等。對(duì)于值類型關(guān)系等號(hào)“==”判斷兩者是否值相等(結(jié)構(gòu)類型和枚舉類型沒(méi)有定義關(guān)系等號(hào)“==”,我們必須自己定義)。對(duì)于引用類型關(guān)系等號(hào)“==”判斷兩者是否引用相等。值類型在C#里通常沒(méi)有引用相等的表示,只有在非托管編程中采用取地址符“&”來(lái)間接判斷二者的地址是否相等。

靜態(tài)方法Equals(object objA,object objB)首先檢查兩個(gè)對(duì)象objA和objB是否都為null,如果是則返回true,否則進(jìn)行objA.Equals(objB)調(diào)用并返回其值。問(wèn)題歸結(jié)到實(shí)例方法Equals(object obj)。該方法缺省的實(shí)現(xiàn)其實(shí)就是{return this= =obj;}也就是判斷兩個(gè)對(duì)象是否引用相等。但我們注意到該方法是一個(gè)虛方法,C#推薦我們重寫此方法來(lái)判斷兩個(gè)對(duì)象是否值相等。實(shí)際上Microsoft.NET框架類庫(kù)內(nèi)提供的許多類型都重寫了該方法,如:System.String(string),System.Int32(int)等,但也有些類型并沒(méi)有重寫該方法如:System.Array等,我們?cè)谑褂脮r(shí)一定要注意。對(duì)于引用類型,如果沒(méi)有重寫實(shí)例方法Equals(object obj),我們對(duì)它的調(diào)用相當(dāng)于this= =obj,即引用相等判斷。所有的值類型(隱含繼承自System.ValueType類)都重寫了實(shí)例方法Equals(object obj)來(lái)判斷是否值相等。

注意對(duì)于對(duì)象x,x.Equals(null)返回false,這里x顯然不能為null(否則不能完成Equals()調(diào)用,系統(tǒng)拋出空引用錯(cuò)誤)。從這里我們也可看出設(shè)計(jì)靜態(tài)方法Equals(object objA,object objB)的原因了–如果兩個(gè)對(duì)象objA和objB都可能為null,我們便只能用object. Equals(object objA,object objB)來(lái)判斷它們是否值相等了–當(dāng)然如果我們沒(méi)有改寫實(shí)例方法Equals(object obj),我們得到的仍是引用相等的結(jié)果。我們可以實(shí)現(xiàn)接口IComparable來(lái)強(qiáng)制改寫實(shí)例方法Equals(object obj)。

對(duì)于值類型,實(shí)例方法Equals(object obj)應(yīng)該和關(guān)系等號(hào)“==”的返回值一致,也就是說(shuō)如果我們重寫了實(shí)例方法Equals(object obj),我們也應(yīng)該重載或定義關(guān)系等號(hào)“==”操作符,反之亦然。雖然值類型(繼承自System.ValueType類)都重寫了實(shí)例方法Equals(object obj),但C#推薦我們重寫自己的值類型的實(shí)例方法Equals(object obj),因?yàn)橄到y(tǒng)的System.ValueType類重寫的很低效。對(duì)于引用類型我們應(yīng)該重寫實(shí)例方法Equals(object obj)來(lái)表達(dá)值相等,一般不應(yīng)該重載關(guān)系等號(hào)“==”操作符,因?yàn)樗娜笔≌Z(yǔ)義是判斷引用相等。

靜態(tài)方法ReferenceEquals(object objA,object objB)判斷兩個(gè)對(duì)象是否引用相等。如果兩個(gè)對(duì)象為引用類型,那么它的語(yǔ)義和沒(méi)有重載的關(guān)系等號(hào)“==”操作符相同。如果兩個(gè)對(duì)象為值類型,那么它的返回值一定是false。

實(shí)例方法GetHashCode()為相應(yīng)的類型提供哈希(hash)碼值,應(yīng)用于哈希算法或哈希表中。需要注意的是如果我們重寫了某類型的實(shí)例方法Equals(object obj),我們也應(yīng)該重寫實(shí)例方法GetHashCode()–這理所應(yīng)當(dāng),兩個(gè)對(duì)象的值相等,它們的哈希碼也應(yīng)該相等。下面的代碼是對(duì)前面幾個(gè)方法的一個(gè)很好的示例:

using System;
struct A
{
public int count;
}
class B
{
public int number;
}
class C
{
public int integer=0;
public override bool Equals(object obj)
{
C c=obj as C;
if (c!=null)
return this.integer==c.integer;
else
return false;
}
public override int GetHashCode()
{
return 2^integer;
}
}
class Test
{
public static void Main()
{
A a1,a2;
a1.count=10;
a2=a1;

//Console.Write(a1==a2);沒(méi)有定義“==”操作符Console.Write(a1.Equals(a2));//True

Console.WriteLine(object.ReferenceEquals(a1,a2));//False

B b1=new B();B b2=new B();b1.number=10;b2.number=10;Console.Write(b1==b2);//FalseConsole.Write(b1.Equals(b2));//False

Console.WriteLine(object.ReferenceEquals(b1,b2));//False

b2=b1;Console.Write(b1==b2);//TrueConsole.Write(b1.Equals(b2));//TrueConsole.WriteLine(object.ReferenceEquals(b1,b2));//TrueC c1=new C();C c2=new C();c1.integer=10;c2.integer=10;Console.Write(c1==c2);//FalseConsole.Write(c1.Equals(c2));//True

Console.WriteLine(object.ReferenceEquals(c1,c2));//False

c2=c1;Console.Write(c1==c2);//TrueConsole.Write(c1.Equals(c2));//TrueConsole.WriteLine(object.ReferenceEquals(c1,c2));//True }

}

如我們所期望,編譯程序并運(yùn)行我們會(huì)得到以下輸出:

True False
False False False
True True True
False True False
True True True

實(shí)例方法GetType()與typeof的語(yǔ)義相同,它們都通過(guò)查詢對(duì)象的元數(shù)據(jù)來(lái)確定對(duì)象的運(yùn)行時(shí)類型,我們?cè)凇暗谑v 特征與映射”對(duì)此作詳細(xì)的闡述。

實(shí)例方法ToString()返回對(duì)象的字符串表達(dá)形式。如果我們沒(méi)有重寫該方法,系統(tǒng)一般將類型名作為字符串返回。

受保護(hù)的Finalize()方法在C#中有特殊的語(yǔ)義,我們將在“第五講 構(gòu)造器與析構(gòu)器”里詳細(xì)闡述。

受保護(hù)的MemberwiseClone()方法返回目前對(duì)象的一個(gè)“影子拷貝”,該方法不能被子類重寫。“影子拷貝”僅僅是對(duì)象的一份按位拷貝,其含義是對(duì)對(duì)象內(nèi)的值類型變量進(jìn)行賦值拷貝,對(duì)其內(nèi)的引用類型變量進(jìn)行句柄拷貝,也就是拷貝后的引用變量將持有對(duì)同一塊內(nèi)存的引用。相對(duì)于“影子拷貝”的是深度拷貝,它對(duì)引用類型的變量進(jìn)行的是值復(fù)制,而非句柄復(fù)制。例如X是一個(gè)含有對(duì)象A,B引用的對(duì)象,而對(duì)象A又含有對(duì)象M的引用。Y是X的一個(gè)“影子拷貝”。那么Y將擁有同樣的A,B的引用。但對(duì)于X的一個(gè)“深度拷貝”Z來(lái)說(shuō),它將擁有對(duì)象C和D的引用,以及一個(gè)間接的對(duì)象N的引用,其中C是A的一份拷貝,D是B的一份拷貝,N是M的一份拷貝。深度拷貝在C#里通過(guò)實(shí)現(xiàn)ICloneable接口(提供Clone()方法)來(lái)完成。

轉(zhuǎn)自:http://apps.hi.baidu.com/share/detail/14180240
C# 中object sender與EventArgs e
一、了解C#中的預(yù)定義事件處理機(jī)制
在寫代碼前我們先來(lái)熟悉.net框架中和事件有關(guān)的類和委托,了解C#中預(yù)定義事件的處理。
EventArgs是包含事件數(shù)據(jù)的類的基類,用于傳遞事件的細(xì)節(jié)。
EventHandler是一個(gè)委托聲明如下
public delegate void EventHandler( object sender , EventArgs e )
注意這里的參數(shù),前者是一個(gè)對(duì)象(其實(shí)這里傳遞的是對(duì)象的引用,如果是button1的click事件則sender就是button1),后面是包含事件數(shù)據(jù)的類的基類。
下面我們研究一下Button類看看其中的事件聲明(使用WinCV工具查看),以Click事件為例。
public event EventHandler Click;
這里定義了一個(gè)EventHandler類型的事件Click
前面的內(nèi)容都是C#在類庫(kù)中已經(jīng)為我們定義好了的。下面我們來(lái)看編程時(shí)產(chǎn)生的代碼。
private void button1_Click(object sender, System.EventArgs e)
{

}
這是我們和button1_click事件所對(duì)應(yīng)的方法。注意方法的參數(shù)符合委托中的簽名(既參數(shù)列表)。那我們?cè)趺窗堰@個(gè)方法和事件聯(lián)系起來(lái)呢,請(qǐng)看下面的代碼。
this.button1.Click += new System.EventHandler(this.button1_Click);
把this.button1_Click方法綁定到this.button1.Click事件。
下面我們研究一下C#事件處理的工作流程,首先系統(tǒng)會(huì)在為我們創(chuàng)建一個(gè)在后臺(tái)監(jiān)聽(tīng)事件的對(duì)象(如果是 button1的事件那么監(jiān)聽(tīng)事件的就是button1),這個(gè)對(duì)象用來(lái)產(chǎn)生事件,如果有某個(gè)用戶事件發(fā)生則產(chǎn)生對(duì)應(yīng)的應(yīng)用程序事件,然后執(zhí)行訂閱了事件的所有方法。
二、簡(jiǎn)單的自定義事件(1)
首先我們需要定義一個(gè)類來(lái)監(jiān)聽(tīng)客戶端事件,這里我們監(jiān)聽(tīng)鍵盤的輸入。
定義一個(gè)委托。
public delegate void UserRequest(object sender,EventArgs e);
前面的object用來(lái)傳遞事件的發(fā)生者,后面的EventArgs用來(lái)傳遞事件的細(xì)節(jié),現(xiàn)在暫時(shí)沒(méi)什么用處,一會(huì)后面的例子中將使用。
下面定義一個(gè)此委托類型類型的事件
public event UserRequest OnUserRequest;
下面我們來(lái)做一個(gè)死循環(huán)
public void Run() { bool finished=false; do { if (Console.ReadLine()==”h”) { OnUserRequest(this,new EventArgs()); } }while(!finished); }
此代碼不斷的要求用戶輸入字符,如果輸入的結(jié)果是h,則觸發(fā)OnUserRequest事件,事件的觸發(fā)者是本身(this),事件細(xì)節(jié)無(wú)(沒(méi)有傳遞任何參數(shù)的EventArgs實(shí)例)。我們給這個(gè)類取名為UserInputMonitor。
下面我們要做的是定義客戶端的類 首先得實(shí)例化UserInputMonitor類
UserInputMonitor monitor=new UserInputMonitor();
然后我們定義一個(gè)方法。
private void ShowMessage(object sender,EventArgs e)
{
Console.WriteLine(“HaHa!!”);
}
最后要做的是把這個(gè)方法和事件聯(lián)系起來(lái)(訂閱事件),我們把它寫到庫(kù)戶端類的構(gòu)造函數(shù)里。
Client(UserInputMonitor m)
{
m.OnUserRequest+=new UserInputMonitor.UserRequest(this.ShowMessage);
//m.OnUserRequest+=new m.UserRequest(this.ShowMessage);
//注意這種寫法是錯(cuò)誤的,因?yàn)槲惺庆o態(tài)的

}下面創(chuàng)建客戶端的實(shí)例。new Client(monitor);對(duì)了,別忘了讓monitor開(kāi)始監(jiān)聽(tīng)事件。monitor.run();大功告成,代碼如下:

using System; class UserInputMonitor { public delegate void UserRequest(object sender,EventArgs e); //定義委托 public event UserRequest OnUserRequest; //此委托類型類型的事件 public void Run() { bool finished=false; do { if (Console.ReadLine()==”h”) { OnUserRequest(this,new EventArgs()); } }while(!finished); } }
public class Client { public static void Main() { UserInputMonitor monitor=new UserInputMonitor(); new Client(monitor); monitor.Run(); } private void ShowMessage(object sender,EventArgs e) { Console.WriteLine(“HaHa!!”); } Client(UserInputMonitor m) { m.OnUserRequest+=new UserInputMonitor.UserRequest(this.ShowMessage); //m.OnUserRequest+=new m.UserRequest(this.ShowMessage); //注意這種寫法是錯(cuò)誤的,因?yàn)槲惺庆o態(tài)的 } }
三、進(jìn)一步研究C#中的預(yù)定義事件處理機(jī)制
可能大家發(fā)現(xiàn)在C#中有些事件和前面的似乎不太一樣。例如
private void textBox1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{

}this.textBox1.KeyPress+=newSystem.Windows.Forms.KeyPressEventHandler(this.textBox1_KeyPress);這里使用了KeyPressEventArgs而不是EventArgs作為參數(shù)。這里使用了KeyEventHandler委托,而不是EventHandler委托。 KeyPressEventArgs是EventArgs的派生類,而KeyEventHandler的聲明如下public delegate void KeyEventHandler( object sender , KeyEventArgs e ); 是參數(shù)為KeyEventArgs的委托。那為什么KeyPress事件要這么做呢,我們可以從兩個(gè)類的構(gòu)造函數(shù)來(lái)找答案。public EventArgs();public KeyPressEventArgs(char keyChar);這里的keyData是什么,是用來(lái)傳遞我們按下了哪個(gè)鍵的,哈。我在KeyEventArgs中又發(fā)現(xiàn)了屬性public char KeyChar { get; }進(jìn)一步證明了我的理論。下面我們來(lái)做一個(gè)類似的例子來(lái)幫助理解。

四、簡(jiǎn)單的自定義事件(2)
拿我們上面做的例子來(lái)改。
我們也定義一個(gè)EventArgs(類似KeyEventArgs)取名MyEventArgs,定義一個(gè)構(gòu)造函數(shù)public MyEventArgs(char keyChar),同樣我們也設(shè)置相應(yīng)的屬性。代碼如下
using System; class MyMyEventArgs:EventArgs { private char keyChar; public MyMyEventArgs(char keyChar) { this.keychar=keychar; } public char KeyChar { get { return keyChar; } } }
因?yàn)楝F(xiàn)在要監(jiān)聽(tīng)多個(gè)鍵了,我們得改寫監(jiān)聽(tīng)器的類中的do…while部分。改寫委托,改寫客戶端傳遞的參數(shù)。好了最終代碼如下,好累
using System; class MyEventArgs:EventArgs { private char keyChar; public MyEventArgs(char keyChar) { this.keyChar=keyChar; } public char KeyChar { get { return keyChar; } } }
class UserInputMonitor { public delegate void UserRequest(object sender,MyEventArgs e); //定義委托 public event UserRequest OnUserRequest; //此委托類型類型的事件 public void Run() { bool finished=false; do { string inputString= Console.ReadLine(); if (inputString!=”“) OnUserRequest(this,new MyEventArgs(inputString[0])); }while(!finished); } }
public class Client { public static void Main() { UserInputMonitor monitor=new UserInputMonitor(); new Client(monitor); monitor.Run(); } private void ShowMessage(object sender,MyEventArgs e) { Console.WriteLine(“捕捉到:{0}”,e.KeyChar); } Client(UserInputMonitor m) { m.OnUserRequest+=new UserInputMonitor.UserRequest(this.ShowMessage); //m.OnUserRequest+=new m.UserRequest(this.ShowMessage); //注意這種寫法是錯(cuò)誤的,因?yàn)槲惺庆o態(tài)的 } }

總結(jié)

以上是生活随笔為你收集整理的C#Object类型的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。