泛型与操作符重载杂谈
泛型基礎
1.為什么要用泛型類,我們先來看一段代碼:
以交換兩個數為例,可能需要定義多個重載方法
public static void swap(ref int x,ref int y)
{
int temp = x;x=y;y=temp;
}
public static void swap(ref float x,ref float y)
{
float temp = x;x=y;y=temp;
}
public static void swap(ref double x,ref double y)
{
double temp = x;x=y;y=temp;
}
這些方法的實現代碼類似,只是操作的數據類型不同而已,這種方法雖然沒錯,但工作效率低,可維護性差。一但發現錯誤,就不得不在個個地方重復修改。于是有人就會提出一種新的方法,既然C#中object類是其他任何類的基類,那么把方法中的參數類型改為object類型,不就可以交換任何類型的值了?
public static void swap(ref object x,ref object y)
{
object temp = x;x=y;y=temp;
}
這種方法雖然有可取之處,但又會帶來新的麻煩,因為如果對值類型調用此方法,程序需要在值類型與object類之間進行裝箱和拆箱的轉換,頻繁使用會大大降低程序的性能,另外,如果用戶試圖交換兩個不同類型的值(例如一個×××,一個字符串),但這兩種類型是不能交換的,程序能通過編譯,但運行時會出錯。
我們來看下面的代碼:
using System;
namespace p9
{
public class abc
{
public static void Main()
{
int a = 10,b = 20;double c = 0.3,d = 1.25;string e = "我愛";string f ="你們";
fanxing<int>.swap(ref a,ref b);
fanxing<double>.swap(ref c,ref d);
Console.WriteLine("{0} {1},{2} {3},{4}{5}",a,b,c,d,e,f);
}
}
public class fanxing<T>
{
public static void swap(ref T x,ref T y)
{
T temp=x;x=y;y=temp;
}
}
}
上面定義的fanxing<T>就是一個泛型類,<>中的T被稱為類型參數,類型參數T可以被不同的具體類型所替代(泛型類中每一個T都將被相應類型替代),fanxing<int>等被稱為泛型類的構造類型。在Main()方法中,如: fanxing<int>.swap(ref a,ref b); 使用的不是泛型類本身,而是泛型類的構造類型fanxing<int>,泛型類的構造類型和其他類一樣可以通過類型名來調用其靜態成員,或使用new來創建對象,并通過對象來調用其實例成員。
2.泛型的靜態成員
就如其他普通類中的靜態成員(字段和方法)只能被類名(不是類的實例)調用一樣,泛型類中的靜態成員也只能被靜態類的構造類名(不是泛型類名)調用。如果上述代碼中出現以下代碼就會出錯:fanxing<int> a = new fanxing<int>(); a.swap(ref a,ref b); fanxing<T>.swap(ref a,ref b);
對于普通類,一個靜態字段在內存中最多只有一個備份,對于泛型類,為其創建了多少種(不是多少個)構造類型,一個靜態字段就在內存中有多少份備份。和普通類的靜態構造函數在類創建實例時先于其他構造函數執行且只執行一次一樣,泛型類的靜態構造函數也先于其他構造函數執行,不同的是對于不同類型的構造類型(每種構造類型)都要調用一次靜態構造函數,而對于其他構造函數,每一種構造類型有幾個構造類型就調用幾次構造函數。不同類型的構造類型之間不互相影響。如下代碼:
using System
namespace p
{
public class abc
{
public static void Main()
{
Contact<int> c1 = new Contact<int>("趙麗");
Contact<int> c2 = new Contact<int>("湯姆");
Contact<double> c3 = new Contact<double>("李明"); }
}
}
public class Contact<T>
{
private string m_name;
private static int m_objects = 0;
private static int m_classes = 0;
public Contact (string name)
{
Console.WriteLine("構造對象:"+name);
m_name = name;
m_objects++;
Console.WriteLine("Contact<{0}>對象數量:{1}",typeof(T),m_objects);
}
static Contact()
{
Console.WriteLine("構造類Contact<{0}>",typeof(T));
m_classes++;
Console.WriteLine("Contact<{0}>類數量:{1}",typeof(T),m_classes);
}
}
輸出結果為:
構造類Contact<System.Int32>
Contact<System.Int32>類數量:1
構造對象:趙麗
Contact<System.Int32>對象數量:1
構造對象:湯姆
Contact<System.Int32>對象數量:2
構造類Contact<System.Double>
Contact<System.Double>類數量:1
構造對象:李明
Contact<System.Double>對象數量:1
操作符重載
重載操作符的意思就是,重新定義該操作符的運算方法,類似于聲明一個方法,也有形式參數。重載操作符要用到關鍵字operator。C#中重載操作符的語法是: public static 返回類型 operator 操作符 (形式參數)。注意:重載運算符時,必須用到public和static關鍵字,并且形式參數不能為空。
重載一元操作符
可重載的一元操作符有: + - ! ~ ++ -- true false (其中true與false的重載必須同時出現,且返回值類型是bool)
using System;
class BooleanInt
{
private int i;
public int Int
{
get {return i;}
set {i = value;}
}
public BooleanInt()
{}
public BooleanInt(int i)
{Int = i;}
public BooleanInt(BooleanInt bi)
{Int = bi.Int;}
public static BooleanInt operator +(BooleanInt bi)
{return new BooleanInt(bi.Int);}
public static BooleanInt operator -(BooleanInt bi)
{return new BooleanInt(-bi.Int);} // @@@@@
public static bool operator !(BooleanInt bi)
{if (bi.Int ==0)
return true;
return false;}
public static BooleanInt operator~(BooleanInt bi)
{return new BooleanInt( ~bi.Int);}
public static BooleanInt operator ++(BooleanInt bi)
{return new BooleanInt(++bi.Int);}
public static BooleanInt operator --(BooleanInt bi)
{return new BooleanInt(--bi.Int);}
public static bool operator true(BooleanInt bi)
{
if (bi.Int==0)
return false;
return true;
}
public static bool operator false(BooleanInt bi)
{
if (bi.Int==0)
return true;
return false;
}
}
class Test
{
public static void Main()
{
BooleanInt bi = new BooleanInt(10);
Console.WriteLine("bi:{0}",bi.Int);
bi=+bi;
Console.WriteLine("+bi:{0}",bi.Int);
bi=-bi;
Console.WriteLine("-bi:{0}",bi.Int);
Console.WriteLine("!bi:{0}",!bi);
Console.WriteLine("!!bi:{0}",!!bi);
bi=~bi;
Console.WriteLine("~bi:{0}",bi.Int);
BooleanInt newBi = ++bi;
Console.WriteLine("newBi = ++bi:{0},{1}",newBi.Int,bi.Int);
newBi = --bi;
Console.WriteLine("newBi = --bi:{0},{1}",newBi.Int,bi.Int);
bi = new BooleanInt(1);
if (bi) //調用true重載
Console.WriteLine("true - BooleanInt(1):true");
else
Console.WriteLine("true - BooleanInt(1):false");
bi =new BooleanInt(0);
if (bi) //也是調用true重載,只是true操作符的重載必須也同樣有false操作符的重載
Console.WriteLine("false - BooleanInt(0):true");
else
Console.WriteLine("false - BooleanInt(0):false");
Console.Read();
}
}
輸出結果:
bi:10
+bi:10
-bi:-10
!bi:False
!!bi:True
~bi:9
newBi = ++bi:10,10
newBi = --bi:9,9
true - BooleanInt(1):true
false - BooleanInt(0):false
@@@@@處,return new BooleanInt(-bi.Int); 等同于 BooleanInt a =new BooleanInt(-bi.Int);return a; 就是說先創造一個類的實例,同時調用該類的構造函數,再返回該類的對象,返回值取決于BooleanInt類的ToString()方法的字符串返回值。 例如一下代碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(abc.xie());
Console.ReadLine();
}
}
public class abc
{
public override string ToString() // ToString()是object類的一個方法,每個類都繼承了該方法,如果子類不重寫該方法,該方法返回的是當前類名的字符串形式。
{
Console.Write("ToString()方法用于將數值轉換成字符串,本例為:");
return 123.ToString();
}
public abc(int a)
{
Console.WriteLine("return a,返回對象取決于該對象的ToString()方法");
}
public static abc xie()
{
abc a = new abc(1);
return a;
}
}
}
輸出結果為:
return a,返回對象取決于該對象的ToString()方法
ToString()方法用于將數值轉換成字符串,本例為:123
如果把return 123.ToString();改為return base.ToString(); 那么輸出結果為:
return a,返回對象取決于該對象的ToString()方法
ToString()方法用于將數值轉換成字符串,本例為: ConsoleApplication1.abc
也就是說ToString()方法前面有兩種參數,一是簡單值類型(這時是將簡單值類型轉換為字符串形式),一是base(這時base指的是基類,在此就是object類,而object類定義的 ToString()方法返回的是當前類名的字符串形式)
重載二元操作符
可重載的二元操作符有: + - * / % & | ^ << >> == != > < >= <= (其中==與!= >與< >=與<=的重載必須同時出現,如果重載了==與!=,最好同時重載Equals(),而這又需要重載GetHashCode()。如果重載了 + - * / % & | ^ << >>,那么也就重載了對應的復合值操作符 += -= *= /= %= &= |= ^= <<= >>=)
例如一下代碼:
using System;
class BooleanInt
{
private int i;
public int Int
{
get{return i;}
set{i = value;}
}
public BooleanInt(){}
public BooleanInt(int i)
{Int = i;}
public BooleanInt(BooleanInt bi)
{Int = bi.Int;}
public static BooleanInt operator +(BooleanInt bi1,BooleanInt bi2)
{return new BooleanInt(bi1.Int + bi2.Int);}
public static BooleanInt operator -(BooleanInt bi1,BooleanInt bi2) //@
{return new BooleanInt(bi1.Int + bi2.Int);} /@@
public static bool operator ==(BooleanInt bi1,BooleanInt bi2)
{return bi1.Int==bi2.Int; }
public static bool operator !=(BooleanInt bi1, BooleanInt bi2)
{ return bi1.Int != bi2.Int; }
public override bool Equals(object obj)
{
return base.Equals(obj); //雖然是重載了,但等于沒重載,因為內部仍然用的是基類(這里是object類)的Equals()方法,不過這樣不會出現警告。
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
class test
{
public static void Main()
{
BooleanInt bi1 = new BooleanInt(8);
BooleanInt bi2 = new BooleanInt(2);
Console.WriteLine("bi1:{0} bi2:{1}",bi1.Int,bi2.Int);
BooleanInt bi = bi1 + bi2;
Console.WriteLine("bi1 + bi2 ={0}",bi.Int);
bi -= bi1; //由于上面@處重載了-,所以-=也被相應的重載了。
Console.WriteLine("bi -= bi1:{0}",bi.Int); //驗證了,重載是重新定義操作符的算法,@@處雖然重載了-,但重載的算法是加法。
Console.WriteLine("bi!=bi1:{0}",bi!=bi1);
Console.Read();
}
}
重載轉換運算符
語法: public static (implicit|explicit) operator 返回類型(當前類名 變量){具體轉換}
implicit聲明轉換符為隱式 explicit聲明轉換符為顯式
using System;
class BooleanInt
{
private int i;
public int Int
{
get{return i;}
set{i = value;}
}
public BooleanInt(){}
public BooleanInt(int i)
{Int = i;}
public BooleanInt(BooleanInt bi)
{Int = bi.Int;}
public static explicit operator int(BooleanInt bi) //重載(int) 重載后(int)就能把BooleaInt類型的值顯式的轉換成int類型了。
{return (int)bi.Int;}
}
class test
{
public static void Main()
{
BooleanInt bi = new BooleanInt(8);
int a= (int)bi;
Console.WriteLine(a);
Console.Read();
}
}
http://blog.csdn.net/kendezhu/article/details/4915129
轉載于:https://blog.51cto.com/flydragon0815/674582
總結
以上是生活随笔為你收集整理的泛型与操作符重载杂谈的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 程序、进程、线程之间的区别
- 下一篇: 2011年9月最新整理的10个有趣的jQ