精通C#--高级C#编程结构

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/x13262608581/article/details/81230382

集合与泛型

集合类:
–非泛型集合【System.Collections,System.Collections.Specialized】
–泛型集合【System.Collections.Generic】

非泛型集合

ArrayList
BitArray
Hashtable
Queue
SortedList
Stack

HybridDictionary
ListDictionary
StringCollection
BitVector32

相关接口:
ICollection 为所有非泛型集合类型定义基本特性
ICloneable 为实现它的对象,向调用者返回对象的副本
IDictionary 允许非泛型集合对象使用名称/值对来表示其内容
IEnumerable
IEnumerator
IList

2.非泛型集合一般针对的对象类型是System.Object

3.
装箱:把值类型数据保存在引用类型变量中。

static void SimpleBoxUnboxOperation()
{
    int myInt = 25;
    // 显式地将值类型分配给System.Object变量的过程
    // 对值类型进行装箱时,CLR会在堆上分配新的对象并且将值类型的值复制到那个实例上。因此,返回给我们的就是新分配在堆上的对象的引用。
    object boxedInt = myInt;
}

拆箱:把保存在对象引用中的值转换回栈上的相应值类型。

static void SimpleBoxUnboxOperation()
{
    int myInt = 25;
    object boxedInt = myInt;
    // CLR会验证收到的值类型是不是等价于装箱的类型。
    // 如果是,就将值复制回本地栈变量上。
    // 如果不是,将抛出InvalidCastException异常。
    int unboxedInt = (int)boxedInt;
}

在传递给需要object的方法时,值类型会自动装箱。

static void WorkWithArrayList()
{
    ArrayList myInts = new ArrayList();
    // 在传递给需要object的方法时,值类型会自动装箱
    myInts.Add(10);
    myInts.Add(20);
    myInts.Add(35);

    // 当将object转换回栈数据时,会发送拆箱
    int i = (int)myInts[0];
    Console.WriteLine("Value of your int:{0}", i);
}

装箱和拆箱时细节:
在托管堆上分配一个新对象
基于栈数据的值必须被转移到新分配的内存位置
在拆箱时,保存在堆对象中的值必须转移回栈
堆上无用的对象【最后】会被回收

泛型集合

1.
与非泛型容器相比,泛型容器的一些优势
提供了更好的性能,因为没有装箱和拆箱过程
更类型安全,因为只包含我们指定的类型
大幅减少了构建自定义集合类型的需要

2.只有类,结构,接口,委托可以使用泛型,枚举类型不可以。
泛型的类型参数的名称可以随意取。但通常,T表示类型,TKey或K表示键,TValue或V表示值。

3.非泛型接口指定类型参数

// 非泛型版本
public interface IComparable
{
    int CompareTo(object obj);
}

// 泛型版本
public interface IComparable<T>
{
    int CompareTo(T obj);
}

public class Car : IComparable<Car>
{
    ...
    // IComparable<T>的实现
    int IComparable<Car>.CompareTo(Car obj)
    {
        if(this.CarID > obj.CarID)
            return 1;
        if(this.CarID < obj.CarID)
            return -1;
        else
            return 0;
    }
}

4.System.Collections.Generic

// 泛型接口
ICollection<T>
ICompare<T>
IDictionary<TKey, TValue>
IEnumerable<T>
IEnumerator<T>
IList<T>
ISet<T>

// 泛型类
Dictionary<TKey, TValue>
LinkedList<T>
List<T>
Queue<T>
SortedDictionary<TKey, TValue>
SortedSet<T>
Stack<T>
HashSet<T>

5.
对象初始化语法。
集合初始化语法:
只能对支持Add()方法的类使用集合初始化语法。

// 初始化标准数组
int[] myArrayOfInts = {0, 1, 2, 3};
// 初始化int的泛型List<>
List<int> myGenericList = new List<int>{0, 1, 2, 3};
// 用数字数据初始化ArrayList
ArrayList myList = new ArrayList{0, 1, 2, 3};

// 综合使用对象初始化和集合初始化
List<Point> myListOfPoints = new List<Point>
{
    new Point{X=2, Y=2},
    new Point{X=3, Y=3},
    new Point(PointColor.BloodRed){X=4, Y=4}
};

6.System.Collections.ObjectModel

ObservableCollection<T>     添加,移除项或刷新整个列表时提供通知的动态数据集合
ReadOnlyObservableCollection<T>


// ObservableCollection<T>实现了与List<T>相同的核心接口。不同的是,ObservableCollection<T>实现了一个名为CollectionChanged的事件。该事件将在插入新项,移除当前项或修改整个集合时触发。
// CollectionChanged定义为委托【这里为NotifyCollectionChangedEventHandler】
// 该委托可以调用任何以object为第一个参数,以NotifyCollectionChangedEventArgs为第二个参数的方法
class Program
{
    static void Main()
    {
        ObservableCollection<Person> people = new ObservableCollection<Person>()
        {
            new Person{FirstName="Peter", LastName="Murphy", Age=52},
            new Person{FirstName="Kevin", LastName="Key", Age=48},
        };

        people.CollectionChanged += people_CollectionChanged;
    }

    static void people_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        Console.WriteLine("Action for this event:{0}", e.Action);
        if(e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
        {
            Console.WriteLine("Here are the OLD items:");
            foreach (Person p in e.OldItems)
            {
                Console.WriteLine(p.ToString());
            }

            Console.WriteLine();
        }

        if(e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
        {
            Console.WriteLine("Here are the NEW items:");
            foreach(Person p in e.NewItems)
            {
                Console.WriteLine(p.ToString());
            }
        }
    }
} 

7.自定义泛型方法

static void Swap<T>(ref T a, ref T b)
{
    Console.WriteLine("You sent the Swap() method a {0}", typeof(T));
    T temp;
    temp = a;
    a = b;
    b = temp;
}

static void Main()
{
    Console.WriteLine("******Fun with custom Generic Methods ******\n");
    int a = 10, b = 90;
    Console.WriteLine("Before swap:{0}, {1}", a, b);
    Swap<int>(ref a, ref b);
    Console.WriteLine("After swap:{0}, {1}", a, b);
    Console.WriteLine();

    string s1 = "Hello", s2 = "There";
    Console.WriteLine("Before swap:{0} {1}", s1, s2);
    Swap<string>(ref s1, ref s2);
    Console.WriteLine("After swap:{0} {1}", s1, s2);
    Console.ReadLine();
}

当使用泛型时,不指定类型参数时,编译器会基于成员参数推断类型参数。
类型参数推断只在泛型方法至少有一个参数时起作用。

8.自定义泛型结构和类

public struct Point<T>
{
    private T xPos;
    private T yPos;
    public Point(T xVal, T yVal)
    {
        xPos = xVal;
        yPos = yVal;
    }

    public T X
    {
        get{return xPos;}
        set{xPos = value;}
    }

    public T Y
    {
        get{return xPos;}
        set{xPos = value;}
    }

    public override string ToString()
    {
        return string.Format("[{0},{1}]", xPos, yPos);
    }

    public void ResetPoint()
    {
        // default(类型参数) 返回一个类型参数的默认值
        xPos = default(T);
        yPos = default(T);
    }
}

9.类型参数的约束
任何泛型项须至少有一个类型参数,并在与泛型类型或参数交互时指定该类型参数。
使用where可以对给定的类型参数添加一组约束。
where T : ???
???:
struct 类型参数T须在其继承链中包含System.ValueType值类型。
class 类型参数T不能在其继承链中包含System.ValueType值类型。
new() 类型参数T须包含一个默认的构造函数。【在有多个约束的类型上,此约束须列在末尾】
NameOfBaseClass 类型参数T须派生于NameOfBaseClass指定的类
NameOfInterface 类型参数T须实现NameOfInterface指定的接口

// 类型参数T为引用类型,且实现了IDrawable,且具备默认构造
// 要为多个类型参数指定多个约束集时,用多个where语句
// where也可以用在限制泛型方法中的类型参数
public class MyGenericClass<T> where T : class, IDrawable, new()
{
    ...
}

目前版本不支持对泛型的类型参数应用C#操作符

猜你喜欢

转载自blog.csdn.net/x13262608581/article/details/81230382