C#Object类型
在C#中,Object類型是所有類型的根,大家平常開發(fā)中都要跟它打交道,但不見得對它里面的每個方法都知根知底,下面對它里面的每個方法都進(jìn)行仔細(xì)的總結(jié)。
概述:
構(gòu)造函數(shù)
Equals函數(shù)
Finalize函數(shù)
GetHashCode函數(shù)
GetType()函數(shù)
ReferenceEquals函數(shù)
MemberWiseClone()函數(shù)
ToString()函數(shù)
Object類型中一共有8個方法,重載的方法沒有算進(jìn)來。下面一一來看看這些方法。
1、構(gòu)造函數(shù)
函數(shù)簽名:public Object()
作用:這個就不用多說了
注意點(diǎn):直接使用new Object()可以用來創(chuàng)建對象;如果非Object類型,則在該類型的構(gòu)造函數(shù)被調(diào)用時,該函數(shù)自動被調(diào)用。
2、Equals函數(shù),該方法有重載函數(shù)
函數(shù)簽名:public virtual bool Equals(Object obj)
public static bool Equals(Object objA,Object objB)
先來看看public virtual bool Equals(Object obj),從簽名里就可以看出來,這個方法是用來開放給繼承類去根據(jù)實(shí)際情況重寫的。
注意點(diǎn):
1)默認(rèn)情況下,對于引用類型,該方法對比的時引用的地址,對于值類型,對比的是值的二進(jìn)制描述是否相同。100.0與100雖然都是100,但是它們的二進(jìn)制分布是不一樣的。
2)不管是引用類型還是值類型,重寫該方法的主要目的都是實(shí)現(xiàn)根據(jù)值來判斷對象是否相等。
3)該方法本身只支持原子類型的比較以及簡單對象的比較,如果是自定義復(fù)雜的類型,則有必要重寫該方法。
4)重寫該方法時,應(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()方法時,不應(yīng)該拋出異常;
6)實(shí)現(xiàn)IComparable接口的話,一定記得重寫Equals方法;
7)如果重寫了Equals(),則一般情況也必須重寫GetHashCode(),不然如果把該類型的對方放在hashtable結(jié)構(gòu)上的話可能產(chǎn)生問題;
8)如果對==進(jìn)行了操作符重載,則記得一定重寫Equals();按照這樣的設(shè)計(jì)方法,類型代碼在調(diào)用Equals時的運(yùn)行結(jié)果,能夠跟應(yīng)用程序調(diào)用==時的結(jié)果保持一致。
看完了public virtual bool Equals(Object obj),我們接著來看看它的重載方法public static bool Equals(Object objA,Object objB)
該方法返回true的條件:
1)objA和objB是同一個實(shí)例
2)objA和objB都是null
3)objA.Equas(objB)返回true
注意上面三個條件是||的關(guān)系
對比這兩個Equals方法,還是很容易對比出不同點(diǎn)的。
3、Finalize函數(shù)
函數(shù)簽名:protected virtual void Finalize()
作用:允許對象在垃圾回收回收該對象之前嘗試釋放資源并執(zhí)行其它清理操作。
注意點(diǎn):
Finalize 是受保護(hù)的,因此只能通過此類或派生類訪問它。
對象變?yōu)椴豢稍L問后將自動調(diào)用此方法,除非已通過 SuppressFinalize 調(diào)用使對象免除了終結(jié)。在應(yīng)用程序域的關(guān)閉過程中,對沒有免除終結(jié)的對象將自動調(diào)用 Finalize,即使那些對象仍是可訪問的。對于給定的實(shí)例僅自動調(diào)用 Finalize 一次,除非使用 ReRegisterForFinalize 這類機(jī)制重新注冊該對象并且后面沒有調(diào)用 GC.SuppressFinalize。
派生類型中的每個 Finalize 實(shí)現(xiàn)都必須調(diào)用其基類型的 Finalize 實(shí)現(xiàn)。這是唯一一種允許應(yīng)用程序代碼調(diào)用 Finalize 的情況。
Finalize 操作具有下列限制:
垃圾回收過程中執(zhí)行終結(jié)器的準(zhǔn)確時間是不確定的。不保證資源在任何特定的時間都能釋放,除非調(diào)用 Close 方法或 Dispose 方法。
即使一個對象引用另一個對象,也不能保證兩個對象的終結(jié)器以任何特定的順序運(yùn)行。即,如果對象 A 具有對對象 B 的引用,并且兩者都有終結(jié)器,則當(dāng)對象 A 的終結(jié)器啟動時,對象 B 可能已經(jīng)終結(jié)了。
運(yùn)行終結(jié)器的線程是未指定的。
在下面的異常情況下,Finalize 方法可能不會運(yùn)行完成或可能根本不運(yùn)行:
另一個終結(jié)器無限期地阻止(進(jìn)入無限循環(huán),試圖獲取永遠(yuǎn)無法獲取的鎖,諸如此類)。由于運(yùn)行時試圖運(yùn)行終結(jié)器來完成,所以如果一個終結(jié)器無限期地阻止,則可能不會調(diào)用其他終結(jié)器。
進(jìn)程終止,但不給運(yùn)行時提供清理的機(jī)會。在這種情況下,運(yùn)行時的第一個進(jìn)程終止通知是 DLL_PROCESS_DETACH 通知。
在關(guān)閉過程中,只有當(dāng)可終結(jié)對象的數(shù)目繼續(xù)減少時,運(yùn)行時才繼續(xù) Finalize 對象。
如果 Finalize 或 Finalize 的重寫引發(fā)異常,并且運(yùn)行庫并非寄宿在重寫默認(rèn)策略的應(yīng)用程序中,則運(yùn)行庫將終止進(jìn)程,并且不執(zhí)行任何活動的 try-finally 塊或終結(jié)器。如果終結(jié)器無法釋放或銷毀資源,此行為可以確保進(jìn)程完整性。
對實(shí)現(xiàn)者的說明:
默認(rèn)情況下,Object..::.Finalize 不執(zhí)行任何操作。只有在必要時才必須由派生類重寫它,因?yàn)槿绻仨氝\(yùn)行 Finalize 操作,垃圾回收過程中的回收往往需要長得多的時間。
如果 Object 保存了對任何資源的引用,則 Finalize 必須由派生類重寫,以便在垃圾回收過程中,在放棄 Object 之前釋放這些資源。
當(dāng)類型使用文件句柄或數(shù)據(jù)庫連接這類在回收使用托管對象時必須釋放的非托管資源時,該類型必須實(shí)現(xiàn) Finalize。有關(guān)輔助和具有更多控制的資源處置方式,請參見 IDisposable 接口。
Finalize 可以采取任何操作,包括在垃圾回收過程中清理了對象后使對象復(fù)活(即,使對象再次可訪問)。但是,對象只能復(fù)活一次;在垃圾回收過程中,不能對復(fù)活對象調(diào)用 Finalize。
析構(gòu)函數(shù)是執(zhí)行清理操作的 C# 機(jī)制。析構(gòu)函數(shù)提供了適當(dāng)?shù)谋Wo(hù)措施,如自動調(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)不保證針對不同的對象返回唯一值。而且,.NET Framework 不保證 GetHashCode 方法的默認(rèn)實(shí)現(xiàn)以及它所返回的值在不同版本的 .NET Framework 中是相同的。因此,在進(jìn)行哈希運(yùn)算時,該方法的默認(rèn)實(shí)現(xiàn)不得用作唯一對象標(biāo)識符。
GetHashCode 方法可以由派生類型重寫。值類型必須重寫此方法,以提供適合該類型的哈希函數(shù)和在哈希表中提供有用的分布。為了獲得最佳結(jié)果,哈希代碼必須基于實(shí)例字段或?qū)傩?#xff08;而非靜態(tài)字段或?qū)傩?#xff09;的值。
用作 Hashtable 對象中鍵的對象還必須重寫 GetHashCode 方法,因?yàn)檫@些對象必須生成其各自的哈希代碼。如果用作鍵的對象不提供 GetHashCode 的有用實(shí)現(xiàn),您可以在構(gòu)造 Hashtable 對象時指定哈希代碼提供程序。在 .NET Framework 2.0 版之前,哈希代碼提供程序是基于 System.Collections..::.IHashCodeProvider 接口的。從 2.0 版開始,哈希代碼提供程序基于 System.Collections..::.IEqualityComparer 接口。
對實(shí)現(xiàn)者的說明:
哈希函數(shù)用于快速生成一個與對象的值相對應(yīng)的數(shù)字(哈希代碼)。哈希函數(shù)通常是特定于每個 Type 的,而且,必須至少使用一個實(shí)例字段作為輸入。
哈希函數(shù)必須具有以下特點(diǎn):
如果兩個對象的比較結(jié)果相等,則每個對象的 GetHashCode 方法都必須返回同一個值。但是,如果兩個對象的比較結(jié)果不相等,則這兩個對象的 GetHashCode 方法不一定返回不同的值。
一個對象的 GetHashCode 方法必須總是返回同一個哈希代碼,但前提是沒有修改過對象狀態(tài),對象狀態(tài)用來確定對象的 Equals 方法的返回值。請注意,這僅適用于應(yīng)用程序的當(dāng)前執(zhí)行,再次運(yùn)行該應(yīng)用程序時可能會返回另一個哈希代碼。
為了獲得最佳性能,哈希函數(shù)必須為所有輸入生成隨機(jī)分布。
例如,String 類提供的 GetHashCode 方法的實(shí)現(xiàn)為相同的字符串值返回相同的哈希代碼。因此,如果兩個 String 對象表示相同的字符串值,則它們返回相同的哈希代碼。另外,該方法使用字符串中的所有字符生成相當(dāng)隨機(jī)的分布式輸出,即使當(dāng)輸入集中在某些范圍內(nèi)時(例如,許多用戶可能有只包含低位 128 個 ASCII 字符的字符串,即使字符串可以包含 65,535 個 Unicode 字符中的任何字符)。
對于 Object 的派生類,當(dāng)且僅當(dāng)此派生類將值相等性定義為引用相等并且類型不是值類型時,GetHashCode 方法才可以委托給 Object..::.GetHashCode 實(shí)現(xiàn)。
在類上提供好的哈希函數(shù)可以顯著影響將這些對象添加到哈希表的性能。在具有好的哈希函數(shù)實(shí)現(xiàn)的哈希表中,搜索元素所用的時間是固定的(例如運(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)必須不會導(dǎo)致循環(huán)引用。例如,如果 ClassA.GetHashCode 調(diào)用 ClassB.GetHashCode,ClassB.GetHashCode 必須不直接或間接調(diào)用 ClassA.GetHashCode。
GetHashCode 方法的實(shí)現(xiàn)必須不引發(fā)異常。
重寫 GetHashCode 的派生類還必須重寫 Equals,以保證被視為相等的兩個對象具有相同的哈希代碼;否則,Hashtable 類型可能無法正常工作。
示例
在某些情況下,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;
}
}
一個類型常具有多個可以參與生成哈希代碼的數(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) 合并該類型的字段以生成哈希代碼。注意,在該代碼示例中,字段表示用戶定義的類型,每個類型都實(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)行時類型。
注意點(diǎn):
對于具有相同運(yùn)行時類型的兩個對象 x 和 y,雖然Object.ReferenceEquals(x,y)返回的是false,但是 Object.ReferenceEquals(x.GetType(),y.GetType()) 返回 true。
Type 對象公開與當(dāng)前 Object 的類關(guān)聯(lián)的元數(shù)據(jù)。
下面的代碼示例說明 GetType 返回當(dāng)前實(shí)例的運(yùn)行時類型。
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 )
作用:判斷兩個指定的對象實(shí)例是否是同一個實(shí)例。從描述也可以看出來,如果參數(shù)是值類型,則會裝箱,比較的是裝箱后的對象實(shí)例。
注意:
如果 objA 是與 objB 是相同的實(shí)例,或者如果二者都為空引用,則為 true;否則為 false。
下面的代碼示例使用 ReferenceEquals 確定兩個對象是否是相同的實(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)建一個淺表副本,方法是創(chuàng)建一個新對象,然后將當(dāng)前對象的非靜態(tài)字段復(fù)制到該新對象。如果字段是值類型的,則對該字段執(zhí)行逐位復(fù)制。如果字段是引用類型,則復(fù)制引用但不復(fù)制引用的對象;因此,原始對象及其復(fù)本引用同一對象。非靜態(tài)字段屬于整個類,不管是深拷貝,還是淺拷貝,都是不需要處理的。并且需要注意該方法是protected的,即只有在類本身內(nèi)部,或者它的繼承者內(nèi)部才能夠調(diào)用它。
例如,考慮一個名為 X 的對象,該對象引用對象 A 和 B。對象 B 又引用對象 C。X 的淺表副本創(chuàng)建一個新對象 X2,該對象也引用對象 A 和 B。與此相對照,X 的深層副本創(chuàng)建一個新對象 X2,該對象引用新對象 A2 和 B2,它們分別是 A 和 B 的副本。B2 又引用新對象 C2,C2 是 C 的副本。使用實(shí)現(xiàn) ICloneable 接口的類執(zhí)行對象的淺表或深層復(fù)制。
下面的代碼示例說明如何使用 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()
作用:返回一個代表當(dāng)前對象的字符串
注意:默認(rèn)情況下返回的是該對象所屬類型的全名稱。繼承類可以重寫該方法,以便自定義顯示輸出內(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#中的類得以單根繼承。如果我們沒有明確指定繼承類,編譯器缺省認(rèn)為該類繼承自System.Object類。System.Object類也可用小寫的object關(guān)鍵字表示,兩者完全等同。自然C#中所有的類都繼承了System.Object類的公共接口,剖析它們對我們理解并掌握C#中類的行為非常重要。下面是僅用接口形式表示的System.Object類:
namespace System
{
public class Object
{
public static bool Equals(object objA,object objB){}
public static bool ReferenceEquals(object objA,object objB){}
我們先看object的兩個靜態(tài)方法Equals(object objA,object objB),ReferenceEquals(object objA,object objB)和一個實(shí)例方法Equals(object obj)。在我們闡述這兩個方法之前我們首先要清楚面向?qū)ο缶幊虄蓚€重要的相等概念:值相等和引用相等。值相等的意思是它們的數(shù)據(jù)成員按內(nèi)存位分別相等。引用相等則是指它們指向同一個內(nèi)存地址,或者說它們的對象句柄相等。引用相等必然推出值相等。對于值類型關(guān)系等號“==”判斷兩者是否值相等(結(jié)構(gòu)類型和枚舉類型沒有定義關(guān)系等號“==”,我們必須自己定義)。對于引用類型關(guān)系等號“==”判斷兩者是否引用相等。值類型在C#里通常沒有引用相等的表示,只有在非托管編程中采用取地址符“&”來間接判斷二者的地址是否相等。
靜態(tài)方法Equals(object objA,object objB)首先檢查兩個對象objA和objB是否都為null,如果是則返回true,否則進(jìn)行objA.Equals(objB)調(diào)用并返回其值。問題歸結(jié)到實(shí)例方法Equals(object obj)。該方法缺省的實(shí)現(xiàn)其實(shí)就是{return this= =obj;}也就是判斷兩個對象是否引用相等。但我們注意到該方法是一個虛方法,C#推薦我們重寫此方法來判斷兩個對象是否值相等。實(shí)際上Microsoft.NET框架類庫內(nèi)提供的許多類型都重寫了該方法,如:System.String(string),System.Int32(int)等,但也有些類型并沒有重寫該方法如:System.Array等,我們在使用時一定要注意。對于引用類型,如果沒有重寫實(shí)例方法Equals(object obj),我們對它的調(diào)用相當(dāng)于this= =obj,即引用相等判斷。所有的值類型(隱含繼承自System.ValueType類)都重寫了實(shí)例方法Equals(object obj)來判斷是否值相等。
注意對于對象x,x.Equals(null)返回false,這里x顯然不能為null(否則不能完成Equals()調(diào)用,系統(tǒng)拋出空引用錯誤)。從這里我們也可看出設(shè)計(jì)靜態(tài)方法Equals(object objA,object objB)的原因了–如果兩個對象objA和objB都可能為null,我們便只能用object. Equals(object objA,object objB)來判斷它們是否值相等了–當(dāng)然如果我們沒有改寫實(shí)例方法Equals(object obj),我們得到的仍是引用相等的結(jié)果。我們可以實(shí)現(xiàn)接口IComparable來強(qiáng)制改寫實(shí)例方法Equals(object obj)。
對于值類型,實(shí)例方法Equals(object obj)應(yīng)該和關(guān)系等號“==”的返回值一致,也就是說如果我們重寫了實(shí)例方法Equals(object obj),我們也應(yīng)該重載或定義關(guān)系等號“==”操作符,反之亦然。雖然值類型(繼承自System.ValueType類)都重寫了實(shí)例方法Equals(object obj),但C#推薦我們重寫自己的值類型的實(shí)例方法Equals(object obj),因?yàn)橄到y(tǒng)的System.ValueType類重寫的很低效。對于引用類型我們應(yīng)該重寫實(shí)例方法Equals(object obj)來表達(dá)值相等,一般不應(yīng)該重載關(guān)系等號“==”操作符,因?yàn)樗娜笔≌Z義是判斷引用相等。
靜態(tài)方法ReferenceEquals(object objA,object objB)判斷兩個對象是否引用相等。如果兩個對象為引用類型,那么它的語義和沒有重載的關(guān)系等號“==”操作符相同。如果兩個對象為值類型,那么它的返回值一定是false。
實(shí)例方法GetHashCode()為相應(yīng)的類型提供哈希(hash)碼值,應(yīng)用于哈希算法或哈希表中。需要注意的是如果我們重寫了某類型的實(shí)例方法Equals(object obj),我們也應(yīng)該重寫實(shí)例方法GetHashCode()–這理所應(yīng)當(dāng),兩個對象的值相等,它們的哈希碼也應(yīng)該相等。下面的代碼是對前面幾個方法的一個很好的示例:
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.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));//FalseConsole.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));//TrueConsole.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)行我們會得到以下輸出:
True False
False False False
True True True
False True False
True True True
實(shí)例方法GetType()與typeof的語義相同,它們都通過查詢對象的元數(shù)據(jù)來確定對象的運(yùn)行時類型,我們在“第十講 特征與映射”對此作詳細(xì)的闡述。
實(shí)例方法ToString()返回對象的字符串表達(dá)形式。如果我們沒有重寫該方法,系統(tǒng)一般將類型名作為字符串返回。
受保護(hù)的Finalize()方法在C#中有特殊的語義,我們將在“第五講 構(gòu)造器與析構(gòu)器”里詳細(xì)闡述。
受保護(hù)的MemberwiseClone()方法返回目前對象的一個“影子拷貝”,該方法不能被子類重寫。“影子拷貝”僅僅是對象的一份按位拷貝,其含義是對對象內(nèi)的值類型變量進(jìn)行賦值拷貝,對其內(nèi)的引用類型變量進(jìn)行句柄拷貝,也就是拷貝后的引用變量將持有對同一塊內(nèi)存的引用。相對于“影子拷貝”的是深度拷貝,它對引用類型的變量進(jìn)行的是值復(fù)制,而非句柄復(fù)制。例如X是一個含有對象A,B引用的對象,而對象A又含有對象M的引用。Y是X的一個“影子拷貝”。那么Y將擁有同樣的A,B的引用。但對于X的一個“深度拷貝”Z來說,它將擁有對象C和D的引用,以及一個間接的對象N的引用,其中C是A的一份拷貝,D是B的一份拷貝,N是M的一份拷貝。深度拷貝在C#里通過實(shí)現(xiàn)ICloneable接口(提供Clone()方法)來完成。
轉(zhuǎn)自:http://apps.hi.baidu.com/share/detail/14180240
C# 中object sender與EventArgs e
一、了解C#中的預(yù)定義事件處理機(jī)制
在寫代碼前我們先來熟悉.net框架中和事件有關(guān)的類和委托,了解C#中預(yù)定義事件的處理。
EventArgs是包含事件數(shù)據(jù)的類的基類,用于傳遞事件的細(xì)節(jié)。
EventHandler是一個委托聲明如下
public delegate void EventHandler( object sender , EventArgs e )
注意這里的參數(shù),前者是一個對象(其實(shí)這里傳遞的是對象的引用,如果是button1的click事件則sender就是button1),后面是包含事件數(shù)據(jù)的類的基類。
下面我們研究一下Button類看看其中的事件聲明(使用WinCV工具查看),以Click事件為例。
public event EventHandler Click;
這里定義了一個EventHandler類型的事件Click
前面的內(nèi)容都是C#在類庫中已經(jīng)為我們定義好了的。下面我們來看編程時產(chǎn)生的代碼。
private void button1_Click(object sender, System.EventArgs e)
{
…
}
這是我們和button1_click事件所對應(yīng)的方法。注意方法的參數(shù)符合委托中的簽名(既參數(shù)列表)。那我們怎么把這個方法和事件聯(lián)系起來呢,請看下面的代碼。
this.button1.Click += new System.EventHandler(this.button1_Click);
把this.button1_Click方法綁定到this.button1.Click事件。
下面我們研究一下C#事件處理的工作流程,首先系統(tǒng)會在為我們創(chuàng)建一個在后臺監(jiān)聽事件的對象(如果是 button1的事件那么監(jiān)聽事件的就是button1),這個對象用來產(chǎn)生事件,如果有某個用戶事件發(fā)生則產(chǎn)生對應(yīng)的應(yīng)用程序事件,然后執(zhí)行訂閱了事件的所有方法。
二、簡單的自定義事件(1)
首先我們需要定義一個類來監(jiān)聽客戶端事件,這里我們監(jiān)聽鍵盤的輸入。
定義一個委托。
public delegate void UserRequest(object sender,EventArgs e);
前面的object用來傳遞事件的發(fā)生者,后面的EventArgs用來傳遞事件的細(xì)節(jié),現(xiàn)在暫時沒什么用處,一會后面的例子中將使用。
下面定義一個此委托類型類型的事件
public event UserRequest OnUserRequest;
下面我們來做一個死循環(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é)無(沒有傳遞任何參數(shù)的EventArgs實(shí)例)。我們給這個類取名為UserInputMonitor。
下面我們要做的是定義客戶端的類 首先得實(shí)例化UserInputMonitor類
UserInputMonitor monitor=new UserInputMonitor();
然后我們定義一個方法。
private void ShowMessage(object sender,EventArgs e)
{
Console.WriteLine(“HaHa!!”);
}
最后要做的是把這個方法和事件聯(lián)系起來(訂閱事件),我們把它寫到庫戶端類的構(gòu)造函數(shù)里。
Client(UserInputMonitor m)
{
m.OnUserRequest+=new UserInputMonitor.UserRequest(this.ShowMessage);
//m.OnUserRequest+=new m.UserRequest(this.ShowMessage);
//注意這種寫法是錯誤的,因?yàn)槲惺庆o態(tài)的
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); //注意這種寫法是錯誤的,因?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)
{
四、簡單的自定義事件(2)
拿我們上面做的例子來改。
我們也定義一個EventArgs(類似KeyEventArgs)取名MyEventArgs,定義一個構(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)聽多個鍵了,我們得改寫監(jiān)聽器的類中的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); //注意這種寫法是錯誤的,因?yàn)槲惺庆o態(tài)的 } }
總結(jié)
以上是生活随笔為你收集整理的C#Object类型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2020年 中国研究生数学建模竞赛B题
- 下一篇: 影刀rpa办公实例一,汇总报名表