2019独角兽企业重金招聘Python工程师标准>>>
集合
- 集合类一般用于处理对象列表,功能大多是通过实现 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
- 如果
是 类 类型,而 也是此类型,或者它继承了此类型,或者它可以封箱到此类型,则结果为 true - 如果
是接口类型,而 也是此类型,或者它是实现此接口的类型,则结果为 true - 如果
是值类型,而 也是此类型,或者它可以拆箱到此类型,则结果为 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.");
}