写了那么多年C#,但一直不知道的事儿系列之2

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指定的接口,多个接口必须用逗号隔开。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值