1.泛型的使用
泛型是一种编程概念,允许你编写可以处理不特定数据类型的代码,从而提高代码的可重用性和类型安全性。泛型允许你编写通用的算法、数据结构和方法,以适应各种不同的数据类型,而不必为每种数据类型编写特定的代码。在 C# 中,泛型主要通过类型参数和泛型类、方法和接口来实现。
创建一个泛型类,其中的一个或多个类型参数允许你在实例化类时指定具体的数据类型。例如:
public class GenericList<T>
{
private List<T> items = new List<T>();
public void Add(T item)
{
items.Add(item);
}
public T Get(int index)
{
return items[index];
}
}
创建泛型方法,这些方法可以在不同数据类型上进行操作。例如:
public T FindMax<T>(T[] array) where T : IComparable
{
if (array.Length == 0)
throw new InvalidOperationException("The array is empty.");
T max = array[0];
foreach (T item in array)
{
if (item.CompareTo(max) > 0)
{
max = item;
}
}
return max;
}
创建泛型接口,以定义可以在不同数据类型上实现的方法。例如:
public interface IRepository<T>
{
void Add(T item);
void Delete(T item);
T GetById(int id);
}
可以使用泛型约束来限制可以在泛型方法或泛型接口上使用的数据类型。例如,where T : IComparable
表示类型 T
必须实现 IComparable
接口。
public T FindMax<T>(T[] array) where T : IComparable
{
// ...
}
泛型在编写通用和类型安全的代码方面非常有用。通过使用泛型,你可以在不同数据类型上实现通用算法,而不必重复编写大量相似的代码。这提高了代码的可维护性和可扩展性。
2.Object类型的使用:
Object
类型是许多编程语言中的通用类型,通常用于存储任意数据类型的对象。它是一种泛型类型,也称为通用类型,允许你在编程时处理各种不同类型的数据。在 C# 中,Object
类型通常被称为 System.Object
,而在其他编程语言中,它可能具有不同的名称,如 Object
或 Any
。
(1)装箱和拆箱: 在 C# 中,将值类型(如整数、浮点数)转换为 Object
类型的过程称为装箱,而将 Object
类型转换回原始值类型的过程称为拆箱。这是因为 Object
类型可以容纳任何数据类型。示例:
int number = 42;
object boxedNumber = number; // 装箱
int unboxedNumber = (int)boxedNumber; // 拆箱
装箱和拆箱可以导致性能开销,因为它们涉及数据类型的转换。
(2)使用 Object 进行多态性: Object
类型可以用于实现多态性,允许你在一个变量中存储不同类的对象,然后在运行时根据对象的实际类型来执行不同的操作。
object shape;
shape = new Circle(); // 存储 Circle 对象
shape = new Rectangle(); // 存储 Rectangle 对象
// 在运行时,根据对象的实际类型执行不同的操作
if (shape is Circle)
{
Circle circle = (Circle)shape;
// 执行与 Circle 相关的操作
}
(3)通用数据容器: Object
类型常用于创建通用的数据容器,例如可以在一个数组或集合中存储不同类型的数据。
List<object> mixedData = new List<object>();
mixedData.Add(42);
mixedData.Add("Hello, World!");
mixedData.Add(new Circle());
foreach (object item in mixedData)
{
// 处理各种不同类型的数据
}
(4)反射: Object
类型在反射中经常使用,因为它可以用于存储反射操作的结果,如获取对象的属性、方法和字段。
object obj = Activator.CreateInstance(typeof(MyClass));
PropertyInfo propertyInfo = obj.GetType().GetProperty("SomeProperty");
object propertyValue = propertyInfo.GetValue(obj);
虽然 Object
类型提供了一种通用的方法来处理不同类型的数据,但它也有一些限制。由于编译时类型信息丢失,因此在运行时需要小心处理数据类型的转换和检查,以避免潜在的类型错误。因此,建议在能够使用强类型的情况下,尽量避免使用 Object
类型,以提高类型安全性。
//值类型转换成引用类型。这个转换称为装箱。相反的过程称为拆箱
int number = 10;
// 装箱
object obj = number;
// 拆箱
number = (int)obj;
Object 类型
> 优点:
> 1. object类型可以用来引用任何类型的实例;
> 2. object类型可以存储任何类型的值;
> 3. 可以定义object类型的参数;
> 4. 可以把object作为返回类型。
> 缺点:
> 1. 会因为程序员没有记住使用的类型而出错,造成类型不兼容;
> 2. 值类型和引用类型的互化即装箱拆箱使系统性能下降
3. 泛型约束
泛型中的数据约束可以指定泛型类型的范围 (泛型约束)
泛型约束总共有五种。
约束 说明
T:结构 类型参数必须是值类型
T:类 类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。
T:new() 类型参数必须具有无参数的公共构造函数。 当与其他约束一起使用时,new() 约束必须最后指定。
T:<基类名> 类型参数必须是指定的基类或派生自指定的基类。
T:<接口名称> 类型参数必须是指定的接口或实现指定的接口。 可以指定多个接口约束。 约束接口也可以是泛型的。
举例:
public class People<T,K,V,W,D,X,G> where T : struct //约束 T 必须是值类型
where K : class //约束 K 必须是引用类型
where V :IMyInterface //约束 V 必须实现 IFace 接口
where W : K //约束 W 必须是 K 类型,或者是 K 类型的子类
where D : MyClass //约束 D 必须是 MyClass 类型,或者是 MyClass类型的子类
where X : class, new() //约束 X 必须是引用类型,并且有一个无参数的构造函数,当有多个约束时,new()必须写在最后
where G : class, IMyInterface,new()
{
public T value { get; set; }
}
泛型默认值问题 需要用 default()方法
4.ArrayList 可变数组
ArrayList的优点:
ArrayList大小是按照其中存储的数据来动态扩充与收缩的
ArrayList 在声明对象时并不需要指定它的长度
ArrayList可以很方便地进行数据的添加插入删除
ArrayList 可以存储任意类型
ArrayList的缺点:
ArrayList在存储数据时使用object类型进行存储的
ArrayList不是类型安全的,使用时很可能出现类型不匹配的错误
就算都插入了同一类型的数据,使用时我们也需要将它们转化为对应的原类型来处理
ArrayList 存储在装箱和拆箱操作,导致其性能低下
List 与其他数组的比较:
List与静态数组(Array类)比较类似,都用于存放一组类型相同的数据。
List与动态数组(ArrayList)比较类似 元素长度不固定。
-
动态大小:
ArrayList
可以在运行时根据需要动态增加或减少其大小,因此你无需提前知道数组的大小。这使得它非常适合处理不确定数量的元素。 -
泛型类型: 从 .NET Framework 2.0 开始,推荐使用泛型集合(如
List<T>
)代替ArrayList
,因为泛型集合提供了更好的类型安全性。但如果你需要与旧代码或.NET Framework 1.1 一起使用,ArrayList
仍然可以使用。 -
支持任意对象类型:
ArrayList
可以存储任何类型的对象,因为它是Object
类型的集合。这意味着你可以将整数、字符串、自定义类的对象等都添加到同一个ArrayList
中。ArrayList list = new ArrayList(); list.Add(42); list.Add("Hello"); list.Add(new CustomObject());
4.方法和属性:
ArrayList
提供了一系列用于添加、删除、查找和遍历元素的方法和属性。例如,你可以使用Add
方法添加元素,使用Remove
方法删除元素,使用Count
属性获取元素的数量等。ArrayList list = new ArrayList(); list.Add(42); list.Add("Hello"); int count = list.Count; // 获取元素数量 list.Remove("Hello"); // 删除元素
-
性能注意事项: 由于
ArrayList
存储的是Object
类型,因此在访问元素时需要进行类型转换,这可能会导致性能开销。如果你知道要存储的元素类型,考虑使用泛型集合,如List<T>
,以避免类型转换开销。List<int> numbers = new List<int>(); // 使用泛型 List 代替 ArrayList numbers.Add(42); // 不需要类型转换
-
总结:
ArrayList
是一种旧的可变数组集合类型,用于存储对象。然而,如果你在 .NET Framework 2.0 或更高版本的环境中编写新代码,更推荐使用泛型集合,以获得更好的类型安全性和性能。
5.Dictionary字典类
Dictionary
是一种在许多编程语言中常见的数据结构,用于存储键-值对(key-value pairs)。在 C# 中,Dictionary
是一个泛型集合,用于存储键和相关联的值,以便能够快速查找、插入和删除数据。以下是关于 C# 中 Dictionary
类的一些重要信息:
-
泛型集合:
Dictionary
是一个泛型集合,它意味着你可以指定键和值的具体数据类型。例如,你可以创建一个Dictionary<int, string>
,其中整数是键,字符串是值。 -
键唯一性: 在
Dictionary
中,每个键都必须是唯一的。这意味着你不能在同一个字典中拥有重复的键。 -
快速查找:
Dictionary
使用哈希表数据结构来存储键-值对,这使得它非常适合快速查找数据。查找特定键对应的值的操作通常是非常高效的,无论字典的大小如何。 -
无序:
Dictionary
中的键-值对是无序的,这意味着它们不会按照特定的顺序存储。如果你需要按顺序访问键或值,你可能需要进行额外的操作,如排序。 -
方法和属性:
Dictionary
提供了一系列方法和属性,用于添加、删除、查找和遍历键-值对。一些常用的方法包括Add
用于添加键-值对,Remove
用于删除键-值对,TryGetValue
用于尝试获取与特定键关联的值等。Dictionary<int, string> dict = new Dictionary<int, string>(); dict.Add(1, "One"); dict.Add(2, "Two"); string value; if (dict.TryGetValue(1, out value)) { Console.WriteLine("Value for key 1: " + value); }
-
初始化: 在 C# 中,你可以使用对象初始化器来初始化
Dictionary
。Dictionary<int, string> dict = new Dictionary<int, string> { { 1, "One" }, { 2, "Two" }, };
总之,Dictionary
是 C# 中用于存储键-值对的强大数据结构,它提供了高效的查找操作,以及丰富的方法和属性来操作字典中的数据。这使得它成为处理键值对集合的常见选择,特别适用于需要快速查找和检索数据的情况。