26、接口实现命名冲突:通过使用显示接口来解决,即,在实现接口时,参考:ReturnType InterfaceName.MethodName(params);同时,需要使用显示转换来访问需要的功能。
27、【.NET 基础类库预定义接口】构建可枚举类型IEnumerable和IEnumerator,适用foreach关键字允许遍历任何数组类型的内容,若一个类中,某一个属性是一个数组,则只需要将类实现IEnumeable接口的GetEnumerator()方法,在方法中返回该属性的GetEnumerator()方法即可。【当该属性为私有属性时适用,否则,直接在foreach处用该属性既可以】
public class PartialClass :IEnumerable
{
private string[] stringArr = new string[4];
public PartialClass()
{
stringArr = new string[] { "s1", "s2", "s3", "s4" };
Console.WriteLine("PartialClass");
}
IEnumerator IEnumerable.GetEnumerator()
{
return stringArr.GetEnumerator();
}
}
28、用yield关键字构建迭代器方法,当我们希望返回能被foreach语法处理的局部数据时,该语法很有用。
yield官方说明:
如果你在语句中使用yield
上下文关键字,则意味着它在其中出现的方法、运算符或get
访问器是迭代器。 通过使用yield
定义迭代器,可在实现自定义集合类型的 IEnumerator<T> 和 IEnumerable 模式时无需其他显式类(保留枚举状态的类,有关示例,请参阅 IEnumerator)。
private string[] stringArr = new string[4];
public PartialClass()
{
stringArr = new string[] { "s1", "s2", "s3", "s4" };
Console.WriteLine("PartialClass");
}
public IEnumerable GetArrDatas(bool returnRevesed)
{
if (returnRevesed)
{
for (int i = stringArr.Length; i != 0; i--)
{
yield return stringArr[i - 1];
}
}
else
{
foreach (var s in stringArr)
{
yield return s;
}
}
}
29、【.NET 基础类库预定义接口】构建可克隆的对象(ICloneable),其中,当类中不包含引用类型变量时,可以返回this.MemberwiseClone()方法逐个复制该类中的每一个字段,但如果包括引用类型时,MemberwiseClone()将这些引用复制到对象中(浅复制),若要实现深复制,需要在克隆过程中创建各个引用类型变量的新实例。
30、比较对象之IComparable和IComparer,IComparable接口,需要实现CompareTo方法,分别用1,-1和0判断两个对象的大小,1是大于,-1是小于,0是等于;当需要指定多个排序顺序时,使用IComparer接口,与IComparable接口不同,IComparer接口不是在要排序的类型中,而是在许多辅助类中实现,其中每个排序各有一个依据(如昵称、ID等)。
//辅助类的实现
public class PetNameComparer :IComparer
{
int IComparer.Compare(object o1,object o2){
Car t1 = o1 as Car;
Car t3 = o2 as Car;
if(t1 != null && t2 != null)
return String.Compare(t1.PetName,t2.PetName);
else
throw new ArgumentExpectiong("Parameter is not a car");
}
}
//使用
Array.Sort(list,new PetNameComparer);
//自定义属性、自定义排序类型
//在类型里
public class Car : IComparable
{
...
public static IComparer SortByPetName
{ get { return (IComparer) new PetNameComparer();}}
}
//使用
Array.Sort(list,Car.SortByPetName);
31、集合,泛型集合与非泛型集合
装箱与拆箱:装箱指显示地将值类型分配给System.Object变量的过程;拆箱就是指把保存在对象引用中的值转换回栈上的相应值类型。
int myInt = 25;
//将int装箱为object引用
object boxedInt = myInt;
//将引用拆箱为相应的int
int unboxedInt = (int) boxedInt;
非泛型集合ArrayList所操作的是System.Object数据,在Add时(在传递给需要object的方法时),实际上值对象会自动装箱,但使用类型索引器从ArrayList中获取项时,则必须使用转换操作,即堆分配的对象拆箱成栈分配的整数,因此当数据量大时,需要考虑性能问题。
推荐使用System.Collections.Generic命名空间下的泛型集合类(Dictionary<TKey,TValue>,List<T>,LinkedList<T>,Queue<T>,SortedDictionary<TKey,TValue>,SortedSet<T>及Stack<T>),优点:
- 泛型提供了更好的性能,因为它们不会导致装箱或拆箱的损耗;
- 泛型更类型安全,因为它们只包含我们指定的类型;
- 泛型大幅减少了构建自定义集合类型的需要,因为基础类库提供了几个预制的容器。
尖括号中标记的正式名称就是类型参数,<T>符号读作 of T;因此IEnumerable<T>读作IEnumerable of T,或也可称其为类型T的枚举。
集合初始化语法:
//初始化标准的数组
int[] myArrayOfInts = {0,1,2,3,4,5};
//初始化整型的泛型List<>
List<int> myGenericList = new List<int> {0,1,2,3,4,5};
//使用数字数据初始化ArrayList
ArrayList myList = new ArrayList {0,1,2,3,4,5};
常用的泛型集合类:
-
Stack<T>类表示以后进先出的方式访问数据;
-
Queue<T>类表示以先进先出的方式访问数据(包括移除对象方法Dequeue(),末尾添加对象方法Enqueue()及返回开始处的对象但不移除方法Peek());
-
SortedSet<T>类中的项是排序的,在插入和移除项之后,也能自动确保排序正确,必须通知SortedSet<T>按何种方式进行排序,可以向构造函数传递一个实现了IComparer<T>泛型接口的参数。
32、泛型中的default,表示一个类型参数的默认值,使用如下:X = default(T);用于设置类型参数的默认值,类型参数的默认值如下:
- 数值的默认值为0;
- 引用类型的默认值为null;
- 一个结构的字段被设定为0(值类型)或null(引用类型)。
33、泛型类型参数的约束where关键字,除非要创建类型安全的自定义集合,否则很少会用到where关键字。
- where T : struct ,作用:该类型参数<T>必须在其继承链中包含System.ValueType值类型, 即必须为结构;
- where T : class ,作用:该类型参数<T>不能在其继承链中包含System.ValueType值类型, 即必须为类型;
- where T : new(),作用:该类型参数<T>必须包含一个默认的构造函数。因为无法预知自定义构造函数的格式。所以如果泛型类型必须创建一个类型参数的实例;
- where T : NameOfBaseClass,作用:该类型参数<T>必须派生于NameOfBaseClass指定的类;
- where T : NameOfInterface,作用:该类型参数<T>必须实现NameOfInterface指定的接口,多个接口必须用逗号隔开。