精通C#--高階C#語言特性
阿新 • • 發佈:2019-02-06
高階C#語言特性
1.索引器
1.1.索引器方法
public class PersonCollection : IEnumerable
{
private ArrayList arPeople = new ArrayList();
// 類的自定義索引器
public Person this[int index]
{
get{return (People)arPeople[index];}
set{arPeople.Insert(index, value);};
}
...
}
1.2.使用字串值索引物件
public class PersonCollection : IEnumerable
{
private Dictionary<string, Person> listPeople = new Dictionary<string, Person>();
public Person this[string name]
{
get{ return listPeople[name];}
set{ listPeople[name] = value;}
}
public void ClearPeople ()
{
listPeople.Clear();
}
public int Count
{
get{ return listPeople.Count;}
}
IEnumerator IEnumerable.GetEnumerator()
{
return listPeople.GetEnumerator();
}
}
static void Main()
{
PersonCollectioni myPeople = new PersonCollection();
myPeople["Homer" ] = new Person("Homer", "Simpson", 40);
myPeople["Marge"] = new Person("Marge", "Simpson", 38);
Person homer = myPeople["Homer"];
Console.WriteLine(homer.ToString());
Console.ReadLine();
}
1.3.過載索引器方法
public sealed class DataTableCollection : InternalDataCollectionBase
{
// 過載的索引器
public DataTable this[string name]{get;}
public DataTable this[string name, string tableNamespace]{get;}
public DataTable this[int index]{get;}
}
1.4.多維的索引器
public class SomeContainer
{
private int[,] my2DintArray = new int[10, 10];
public int this[int row, int column]
{}
}
1.5.在介面型別上定義索引器
public interface IStringContainer
{
string this[int index]{get; set;}
}
class SomeClass : IStringContainer
{
private List<string> myStrings = new List<string>();
public string this[int index]
{
get{return myStrings[index];}
set{myStrings.Insert(index, value);}
}
}
操作符過載
C#操作符可過載性
+, -, !, ~, ++, --, true, false 可過載
+, -, *, /, %, &, |, ^, <<, >> 可過載
==, !=, <, >, <=, >= 可過載【<和>, <=和>=, == 和 != 過載時要一起】
[] 索引器提供了類似的功能,故,不再支援過載
() 自定義轉換方法提供了同樣的功能,故,不再支援過載
+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>= 不可過載,但相關二元操作符過載時,也隨之具備新功能
operator 允許自定義型別對內建操作符做出不同反應,且只可與static關鍵字聯合使用。
public class Point : IComparable<Point>
{
...
public static Point operator+(Point p1, Point p2)
{
return new Point(p1.X + p2.X, p1.Y + p2.Y);
}
public static Point operator-(Point p1, Point p2)
{
return new Point(p1.X-p2.X, p1.Y-p2.Y);
}
// C#中不能獨立過載前後遞增/遞減。
public static Point operator++(Point p1)
{
return Point(p1.X+1, p1.Y+1);
}
public static Point operator--(Point p1)
{
return new Point(p1.X-1, p1.Y-1);
}
// System.Object.Equals()可以重寫,實現引用型別間基於值的比較
// 如果選擇重寫Equals和與之密切相關的System.Object.GetHashCode,則,再過載==和!=意義不大
public override bool Equals(object o)
{
if(o == null) return false;
return o.ToString() == this.ToString();
}
public override int GetHashCode()
{
return this.ToString().GetHashCode();
}
public static bool operator==(Point p1, Point p2)
{
return p1.Equals(p2);
}
public static bool operator!=(Point p1, Point p2)
{
return !p1.Equals(p2);
}
// 過載比較操作符
public int CompareTo(Point other)
{
if(this.X > other.X && this.Y > other.Y)
{
return 1;
}
if(this.X < other.X && this.Y < oher.Y)
{
return -1;
}
else
{
return 0;
}
}
public static bool operator<(Point p1, Point p2)
{
return (p1.CompareTo(p2) < 0);
}
public static bool operator>(Point p1, Point p2)
{
return (p1.CompareTo(p2) > 0);
}
public static bool operator<=(Point p1, Point p2)
{
return (p1.CompareTo(p2) <= 0);
}
public static bool operator>=(Point p1, Point p2)
{
return (p1.CompareTo(p2) >= 0);
}
}
//
Point p1 = new Point(10, 10);
Point p2 = new Point(10, 10);
Point p3 = p1 + p2;
Point p4 = Point.operator+(p1, p2);
// 因為過載了+和-,故+=, -=自動具備過載後的表現
自定義型別轉換
1.
C#允許我們構建能使使用者型別響應()操作符的自定義強制型別轉換例程。
2.
public struct Rectangle
{
public int Width{get; set;}
public int Height{get; set;}
public Rectangle(int w, int h) : this()
{
Width = w;
Height = h;
}
public void Draw()
{
for(int i = 0; i < Height; i++)
{
for(int j = 0; j < Width; j++)
{
Console.Write("*");
}
Console.WriteLine();
}
}
public override string ToString()
{
return string.Format("[Width={0}; Height={1}]", Width, Height);
}
}
public struct Square
{
public int Length{get; set;}
public Square(int l) : this()
{
Length = l;
}
public void Draw()
{
for(int i = 0; i < Length; i++)
{
for(int j =0; j < Length; j++)
{
Console.Write("*");
}
Console.WriteLine();
}
}
public override string ToString()
{
return string.Format("[Length={0}]", Length);
}
public static explicit operator Square(Rectangle r)
{
Square s = new Square();
s.Length = r.Height;
return s;
}
public static explicit operator Square(int sideLength)
{
Square newSq = new Square();
newSq.Length = sideLength;
return newSq;
}
public static explicit operator int(Square s)
{
return s.Length;
}
public static implicit operator Rectangle(Square s)
{
Reactangle r = new Rectangle();
r.Height = s.Length;
r.Width = s.Length * 2;
return r;
}
}
3.
轉換例程使用C# operator,結合使用explicit或implicit 且 必須定義為靜態的。
傳入引數是要轉換的實體,操作符型別是轉換後的實體。
擴充套件方法
允許你在不直接修改原始型別下,為類或結構新增新的方法或屬性。
1.定義擴充套件方法
必須把方法定義在靜態類中。故,每一個擴充套件方法須宣告為靜態的。
所有擴充套件方法都要使用this對第一個引數【且僅對第一個引數】進行修飾。
2.
static class MyExtensions
{
// 擴充套件方法的第一個引數表示被拓展的型別。需要用this修飾。
// 後續其它引數,即為方法的普通傳入引數
public static void DisplayDefiningAssembly(this object obj)
{
Console.WriteLine("{0} lives here:=>{1}\n", obj.GetType().Name, Assembly.GetAssembly(obj.GetType()).GetName().Name);
}
public static int ReverseDigits(this int i)
{
char[] digits = i.ToString().ToCharArray();
Array.Reverse(digits);
string newDigits = new string(digits);
return int.Parse(newDigits);
}
}
3.匯入擴充套件方法
在定義包含擴充套件方法的類時,應將其定義在.NET名稱空間中。
如果該命名與使用擴充套件方法的名稱空間不同,就需在使用擴充套件方法的哪裡使用using關鍵字。
4.擴充套件實現了指定介面的型別
static class AnnoyingExtensions
{
public static void PrintDataAndBeep(this System.Collections.IEnumerable iterator)
{
foreach(var item in iterator)
{
Console.WriteLine(item);
Console.Beep();
}
}
}
static void Main()
{
Console.WriteLine("***xxx***\n");
string[] data = {"1", "2", "3"};
data.PrintDataAndBeep();
Console.WriteLine();
List<int> myInts = new List<int>(){10, 15, 20};
myInts.PrintDataAndBeep();
Console.ReadLine();
}
匿名型別
1.定義匿名型別
當定義一個匿名型別時,需使用關鍵字var和物件初始化語法。
static void BuildAnonType(string make, string color, int currSp)
{
var car = new {Make = make, Color = color, Speed = currSp};
Console.WriteLine("You have a {0} {1} going {2} MPH", car.Color, car.Make, car.Speed);
Console.WriteLine("ToString() == {0}", car.ToString());
}
2.
所有的匿名型別都自動繼承System.Object,
匿名型別的型別名完全由編譯器決定。
3.建立由匿名型別組成的匿名型別
var purchaseItem = new
{
TimeBought = DateTime.Now,
ItemBought = new {Color = "Red", Make = "Saab", CurrentSpeed = 55},
Price = 34.000
};
指標型別
1.編譯時,須指定 /unsafe
2.進行指標操作的區域用 unsafe{} 包圍。
class Program
{
static void Main(string[] args)
{
unsafe
{
// 可直接使用指標區域
}
}
}
// 不安全的結構,僅可用於unsafe上下文中
unsafe struct Node
{
public int Value;
public Node* Left;
public Node* Right;
}
// 這個結構可以用在非unsafe上下文,但結構Node2*成員只能用在unsafe上下文。
public struct Node2
{
public int Value;
// 只能在unsafe上下文訪問
public unsafe Node2* Left;
public unsafe Node2* Right;
}
// 此函式只有在不安全上下文才能被呼叫
unsafe static void SquareIntPointer(int* myIntPointer)
{
*myIntPointer *= *myIntPointer;
}
unsafe
{
int *p1, *p2;// X
int* p1, p2;// C#中這裡和C/C++不同。
}
在不安全上下文中,可能需要宣告一個直接從呼叫棧分配記憶體的本地變數。
unsafe static void UnsafeStackAlloc()
{
char* p = stackalloc char[256];
for(int k = 0; k < 256; k++)
p[k] = (char)k;
}
使用fixed關鍵字
class PointRef
{
public int x;
public int y;
public override string ToString()
{
return string.Format("({0}, {1})", x, y);
}
}
class MyTest
{
unsafe public static void UseAndPinPoint()
{
PointRef pt = new PointRef();
pt.x = 5;
pt.y = 6;
// 在適當位置固定pt以免GC除去
fixed(int* p = &pt.x)
{
// 在此使用int*變數
}
}
}
任何時候在不安全程式碼上下文中與引用型別互動,都要固定該引用。
sizeof在不安全程式碼中用於獲取型別尺寸大小。