C#学习速记_集合、比较和转换

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

集合

  • 集合类一般用于处理对象列表,功能大多是通过实现 System.Collections 名称空间中的接口获得
  • 集合类可以是强类型的,提取项时,不需要类型转换,集合类可以提供专用方法
  • 数组为 System.Array 类的实例,他实现了 IList, ICollection 和 IEnumerable ,但不支持 IList 的一些更高级的功能,它表示大小固定的项列表

System.Collections 中的接口

接口 继承关系 提供的功能
IEnumerable 迭代集合中的项
ICollection IEnumerable 获取集合中项的个数,把集合项复制到一个简单的数据类型中
IList ICollection 与 IEnumerable 提供了集合的项代表,允许访问这些项,提供其他与项列表相关的基本功能
IDictionary ICollection 与 IEnumerable 提供了可通过键值访问的项列表

使用集合

System.Array

  • 大小固定,初始化时指定
  • 采用 索引 来定位成员赋值
  • 使用 Length 属性取得数组大小

System.ArrayList

  • 大小可变,初始化时不需要指定
  • 使用 Add 方法增加新成员
  • 使用 Count 属性取得列表大小
  • 使用 RemoveAt(索引),删除指定成员,剩余成员自动向前补位
  • 使用 Remove(成员对象实例),删除指定成员
  • 使用 AddRange(实现ICollection接口的任意成员) 方法,增加成员
  • 使用 IndexOf(成员对象实例),定位成员位置

定义集合

推荐通过继承 System.Collections.CollectionBase 类来实现自己的集合

System.Collections.CollectionBase

  • 实现了 IEmumerable, ICollection, IList 接口
  • 实现了 IList 的 Clear() 与 RemoveAt() 方法
  • 实现了 ICollection 的 Count 属性
  • 提供受保护的 List 与 InnerList 属性,可以访问存储的对象本身
public class Animals : System.Collections.CollectionBase
{
    public void Add(Animal newAnimal)
    {
        List.Add(newAnimal)
    }
    public void Remove(Animal oldAnimal)
    {
        List.Remove(oldAnimal)
    }
    public Animals() {}
}

Animals animalCollection = new Animals();
animalCollection.Add(new Cow("Lea"));

foreach(Animal myAnimal in animalCollection)
{
    Console.WriteLine($"New {myAnimal.ToString()} object added to " +
        $"coustom collection, Name = {myAnimal.Name}");
}

索引符

通过索引方法访问成员


public class Animals : System.Collections.CollectionBase
{
    ...
    
    public Animal this[int animalIndex]
    {
        get { return (Animal)List[animalIndex]; } // 强制类型转换
        set { List[animalIndex] = value; }
    }
}

animalCollection[0].Feed();
    

键控集合和IDictionary

  • 可以通过键值进行成员索引
  • 通过继承 DictionaryBase 来实现
  • DictionaryBase 实现了 Clear() 与 Count
  • 通过 Dictionary 访问存储的对象
public class Animals : System.Collection.DictionaryBase
{
    public void Add(string newID, Animal newAnimal)
    {
        Dictionary.Add(newID, newAnimal);
    }
    
    public void Remove(string animalID)
    {
        Dictionary.Remove(animalID);
    }
    
    public Animals() {}
    
    public Animal this[string animalID]
    {
        get { return (Animal)Dictionary[animalID]; }
        set { Dictionary[animalID] = value;}
    }
}

// 可使用 Value 取得成员,使用 Key 取得键值
foreach(Animal myEntry in animalDictionary)
{
    Console.WriteLine($"New {myEntry.Value.ToString()} object added to " +
        $"coustom collection, Name = {((Animal)myEntry.Value).Name}");
}

迭代器

  • 按顺序提供了要在 foreach 块中使用的所有值
  • 可以是代码块,方法,属性
  • 迭代类时,使用 GetEnumerator() 方法,返回类型是 IEnumerator,
  • 迭代类成员时,使用 IEnumerable
  • 使用 yield return ; 在 foreach 中选择要使用的值
  • 使用 yield break; 中断
public static IEnumerable SimpleList()
{
    yield return "string 1";
    yield return "string 2";
    yield return "string 2";
}

static void Main(string[] args)
{
    foreach (string item in SimpleList())
    {
        Console.WriteLine(item);
    }
    Console.ReadKey();
}

迭代器与集合

// 使用迭代器迭代存储在字典类型中的对象

public class Animals : System.Collection.DictionaryBase
{
    public void Add(string newID, Animal newAnimal)
    {
        Dictionary.Add(newID, newAnimal);
    }
    
    public void Remove(string animalID)
    {
        Dictionary.Remove(animalID);
    }
    
    public Animals() {}
    
    public Animal this[string animalID]
    {
        get { return (Animal)Dictionary[animalID]; }
        set { Dictionary[animalID] = value;}
    }
    
    public new IEnumerator GetEnumerator() // 显示隐藏基类中的实现
    {
        foreach (object animal in Dictionary.Values)
        {
            yield return (Animal)animal;
        }
    }
    
    
}

foreach(Animal myAnimal in animalDictionary)
{
    Console.WriteLine($"New {myAnimal.ToString()} object added to " +
        $"coustom collection, Name = {myAnimal.Name}");
}



深度复制

  • 浅度复制,只能复制值类型
// 浅度复制,通过 MemberwiseClone() 方法

public class Content
{
    public int Val;
}

public class Cloner : ICloneable
{
    public Content MyContent = new Content();
    public Cloner(int newVal)
    {
        MyContent.Val = newVal;
    }
    public object GetCopy() => MemberwiseClone();
}


// 深度复制,继承 ICloneable , 实现 Clone() 方法

public class Content
{
    public int Val;
}

public class Cloner : ICloneable
{
    public Content MyContent = new Content();
    public Cloner(int newVal)
    {
        MyContent.Val = newVal;
    }
    public object Clone()
    {
        Cloner clonedCloner = new Cloner(MyContent.Val);
        return clonedCloner;
        
    }
}

比较

类型比较

if (myObj.GetType() == typeof(MyClass))
{
    // myObj is an instance of the class MyClass.
}

封箱和拆箱

  • 封箱(boxing)是把值类型转换为 Sytem.Object 类型,或者由值类型实现的接口类型
  • 拆箱(unboxing)与此相反
  • 拆箱需要显示类型转换,封箱是隐式的,不需要进行类型转换
  • 优点:允许在成员是 object 类型的集合中使用值类型,允许在值类型上调用 object 方法
  • 在访问值类型内容前,必须进行拆箱

// 示例1,值的副本

struct MyStruct
{
    public int Val;
}

MyStruct myStruct1 = new MyStruct();
myStruct1.Val = 5;

// 封箱
object myObject = myStruct1;

myStruct1.Val = 6;

// 拆箱
MyStruct myStruct2 = (MyStruct)myObject;  // 此种方式创建的是指向包含值类型变量副本的引用
Console.WriteLine($"myStruct1.Val = {myStruct1.Val}");
Console.WriteLine($"myStruct2.Val = {myStruct2.Val}");

结果:
myStruct1.Val = 6
myStruct2.Val = 5


// 示例2,对象的引用

class MyClass
{
    public int Val;
}

MyClass myObj = new MyClass();
myObj.Val = 5;

// 封箱
object myObject1 = myObj; // 对对象的封箱,实际上存储的是对象的引用

myObj.Val = 6;

// 拆箱
MyClass myObject2 = (MyClass)myObject1;
Console.WriteLine($"myObject1.Val = {((MyClass)myObject1).Val}"); // 拆箱转化值前进行强制类型转换
Console.WriteLine($"myObject2.Val = {myObject2.Val}");

结果:
myObject1.Val = 6
myObject2.Val = 6

// 示例3,通过接口进行拆封箱

// 实现接口
interface IMyInterface { }
struct MyStruct : IMyInterface
{
    public int Val;
}

// 通过接口来封箱
MyStruct myStruct1 = new MyStruct();
IMyInterface myInter = myStruct1;

myStruct1.Val = 1;

Console.WriteLine($"myStruct1.Val = {myStruct1.Val}");

// 拆箱
MyStruct myStruct2 = (MyStruct)myInter;
myStruct2.Val = 10;

Console.WriteLine($"myStruct1.Val = {myStruct1.Val}");
Console.WriteLine($"myStruct2.Val = {myStruct2.Val}");

结果:
myStruct1.Val = 1
myStruct1.Val = 1
myStruct2.Val = 10

is 运算符

  • 功能是检查对象是否可以转换为指定类型
 is 

  1. 如果 是 类 类型,而 也是此类型,或者它继承了此类型,或者它可以封箱到此类型,则结果为 true
  2. 如果 是接口类型,而 也是此类型,或者它是实现此接口的类型,则结果为 true
  3. 如果 是值类型,而 也是此类型,或者它可以拆箱到此类型,则结果为 true

值比较

运算符重载

与静态方法声明类似,使用 operator 关键字 与 要重载的 运算符 构成

可以重载的运算符 种类
+,-,!-,~,++,--,true,false 一元运算符
+,-,*,/,%,&, ,^,<<,>>
==,!=,<,>,<=,>= 比较运算符
  • 不同把签名相同的运算符重载定义,添加到涉及到相互运算的多个类中,否则不能确定需要执行那个类中的运算符重载
  • 如果参数的类型不同,操作数的顺序必须与运算符重载的参数顺序相同,否则报错
  • 不能重载赋值运算符,如 =, += 等等
  • 不能重载 && 与 ||
  • 一些运算符需要成对重载,如 > <
  • == 与 != ,需要同时 重写 Object.Equals 与 Object.GetHashCode 方法
  • 重载的 true 与 false,可以直接在布尔表达式中使用

public class Class1
{
    public int val;
    
    public static Class1 operator +(Class1 op1, Class1 op2)
    {
        Class1 retVal = new Class1();
        retVal.val = op1.val + op2.val;
        return retVal;
    }
    
    public static Class1 operator -(Class1 op1)
    {
        Class1 retVal = new Class1();
        retVal.val = -op1.val;
        return retVal;
    }

    public static Class1 operator -(Class1 op1, Class1 op2)
    {
        Class1 retVal = new Class1();
        retVal.val = op1.val - op2.val;
        return retVal;
    }
    
    public override bool Equals(object op1) => val == ((Class1)op1).val; // 参数类型必须是 object,否则就是 重载 这个方法,而不是 重写
    public override int GetHashCode() => val;
}

Class1 op1 = new Class1();
op1.val = 5;

Class1 op2 = new Class1();
op2.val = 5;

Class1 op3 = op1 + op2;

IComparable 和 IComparer

  • IComparable 在要比较的对象的定义类中实现,可以比较此对象与实现该的另一个对象
  • IComparer 在单独的一个类中实现,可以用来比较任意2个对象

// 通过实现 IComparable 接口的 CompareTo 方法,参数为对象,返回值类值为 int

if (person1.CompareTo(person2) == 0)
    ...

// 通过实现 IComparer 接口的 Compare() 方法,参数为2个对象,返回值类型为 int

if (personComparer.Compare(person1, person2) == 0)
    ...

调用 .NET Framework 中的默认实现类 Comparer

  • 来源于 Sytem.Collections 名称空间
  • 可以对简单类型及支持 IComparable 接口的任意类型进行特定文化的比较
  • Comparer.Default.Compare(object1, object2)
// 比较字符串
string firstString = "First String";
string secondString = "Second String";

WriteLine($"Comparing '{firstString}' and '{secondString}', result: {Comparer.Default.Compare(firstString, secondString)}");

// 比较数值
int firstInt = 35;
int secondInt = 23;

WriteLine($"Comparing '{firstInt}' and '{secondInt}', result: {Comparer.Default.Compare(firstInt, secondInt)}");

// 结果

Comparing 'First String' and 'Second String', result: -1
Comparing '35' and '23', result: 1

  • 使用前需要检查对象参数是否支持 IComparable
  • 允许使用 null ,它表示 小于 其他任意对象
  • 字符串要根据 不同文化或言来处理,必须要使用构造函数(传递 System.Globalization.CultrueInfo 对象)来实例化
  • 字符串在处理时要区分大小写,如不区分大小写,要使用 CaseInsensitiveComparer 类

对集合排序

// 类实现 IComparable 接口
public class Person : IComparable
{
    public string Name;
    public int Age;
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
    public int CompareTo(object obj)
    {
        if (obj is Person)
        {
            Person otherPerson = obj as Person;
            return this.Age - otherPerson.Age;
        }
        else
        {
            throw new ArgumentException("Object to compare to is not a Person object.");
        }
    }
}

// 单独定义比较类,实现 IComparer 接口

class PersonComparerName : IComparer
{
    public static IComparer Default = new PersonComparerName();
    public int Compare(object x, object y)
    {
        if (x is Person && y is Person)
        {
            return Comparer.Default.Compare(((Person)x).Name,((Person)y).Name);
        }
        else
        {
            throw new ArgumentException("One or both objects to compare are not Person objects.");
        }
    }
}

// 调用

ArrayList list = new ArrayList();
list.Add(new Person("Rual", 30));
list.Add(new Person("Donna", 25));
list.Add(new Person("Mary", 27));
list.Add(new Person("Ben", 44));

WriteLine("Unsorted people:");
for (int i = 0; i < list.Count; i++)
{
    WriteLine($"{(list[i] as Person).Name}: {(list[i] as Person).Age}");
}

WriteLine("\nPeople sorted with default comparer (by age):");
list.Sort();
for (int i = 0; i < list.Count; i++)
{
    WriteLine($"{(list[i] as Person).Name}: {(list[i] as Person).Age}");
}

WriteLine("\nPeople sorted with nodefault comparer (by name):");
list.Sort(PersonComparerName.Default); // new PersonComparerName()
for (int i = 0; i < list.Count; i++)
{
    WriteLine($"{(list[i] as Person).Name}: {(list[i] as Person).Age}");
}

// 结果

Unsorted people:
Rual: 30
Donna: 25
Mary: 27
Ben: 44

People sorted with default comparer (by age):
Donna: 25
Mary: 27
Rual: 30
Ben: 44

People sorted with nodefault comparer (by name):
Ben: 44
Donna: 25
Mary: 27
Rual: 30


转换

重载转换运算符

  • implicit 隐匿转换
  • explicit 显示转换

public class Class1
{
    public int val;
    public static implicit operator Class2(Class1 op1)
    {
        Class2 retVal = new Class2();
        retVal.val = op1.val;
        return retVal;
    }
}

public class Class2
{
    public double val;
    public static explicit operator Class1(Class2 op1)
    {
        Class1 retVal = new Class1();
        retVal.val = (int)op1.val;
        return retVal;
    }
}

as 运算符

  • 把一种类型转换为指定的引用类型
  • 如果不能转换,结果为 null
 as 

适用场景

  • 的类型是 类型
  • 可以隐藏转换为 类型
  • 可以封箱到 类型中

public void MilkCow(Animal myAnimal)
{
    Cow myCow = myAnimal as Cow; // 如果不是 Cow ,返回 null
    if (myCow != null)
        myCow.Milk();
    else
        WriteLine($"{myAnimal.Name} isn`t a cow, and so can`t be milked.");
}

转载于:https://my.oschina.net/moyung2014/blog/1816687

你可能感兴趣的