精通C#--高级C#语言特性

#高级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#允许我们构建能使用户类型响应()操作符的自定义强制类型转换例程。

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;
	}
}

转换例程使用C# operator,结合使用explicit或implicit 且 必须定义为静态的。
传入参数是要转换的实体,操作符类型是转换后的实体。

#扩展方法
允许你在不直接修改原始类型下,为类或结构添加新的方法或属性。

1.定义扩展方法
必须把方法定义在静态类中。故,每一个扩展方法须声明为静态的。
所有扩展方法都要使用this对第一个参数【且仅对第一个参数】进行修饰。

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());
}

所有的匿名类型都自动继承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在不安全代码中用于获取类型尺寸大小。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

raindayinrain

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值