精通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
{
    ...
    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在不安全代码中用于获取类型尺寸大小。

你可能感兴趣的:(Language-c#)