C#中泛型的应用说明

一、泛型概述

泛型的主要目的是提高代码的复用性和类型安全性,通过使用泛型,可以创建处理任何数据类型的类和方法,而无需为每种数据类型都编写一个单独的类或方法。同时,泛型还可以在编译时提供类型检查,从而避免在运行时出现类型错误。

二、泛型定义

在C#中,我们可以通过在类、接口、方法或委托的名称后面添加尖括号<>来定义泛型。尖括号中包含的类型参数可以是任何有效的C#类型,包括类、结构、接口、委托等。

2.1 泛型方法的声明

   //实现string 转换为其他类型
        public static T TypeConvert<T>(string val)  
        {
            //代码首先检查传入的字符串val是否为空、空白或为null。如果是,则直接返回该类型的默认值(例如,对于引用类型,返回null;对于值类型,返回其默认值,如0或false)。
            if (String.IsNullOrWhiteSpace(val))
                return default(T);
            //如果T是一个枚举类型,则使用Enum.Parse方法将字符串val解析为该枚举类型的值。true参数表示不区分大小写。
            if (typeof(T).IsEnum)
                return (T)Enum.Parse(typeof(T), val, true);
            //如果T不是枚举类型,则使用Convert.ChangeType方法将字符串val转换为T类型。如果转换失败,会抛出异常。
            return (T)Convert.ChangeType(val, typeof(T));
        }

2.1.1.用途

这个方法的主要用途是提供一个通用的字符串到类型的转换功能,适用于各种不同的类型,包括但不限于基本数据类型、枚举类型和自定义类型。它简化了类型转换的代码,使得代码更加简洁和易于维护。

2.2.2.注意事项

a.异常处理:如果Convert.ChangeType方法无法将字符串转换为指定的类型,会抛出InvalidCastException异常。在实际使用中,可能需要添加异常处理代码来捕获并处理这种异常;

b.枚举类型转换Enum.Parse方法在解析枚举值时,如果字符串val不匹配任何枚举成员,会抛出ArgumentException异常。因此,使用此方法时也需要考虑异常处理;

c.性能考虑:对于大量数据的转换,频繁调用此方法可能会影响性能。如果性能是一个关键考虑因素,可能需要寻找更高效的转换方法;

d.类型安全性:使用泛型方法时,编译器无法在编译时检查类型转换的正确性,因此需要在运行时处理可能的异常。

2.2 泛型方法的调用 

 int num = TypeConvert<int>("1");//将字符l类型的1转换成int 类型的数字1

 三、泛型类和泛型接口

3.1 泛型类的声明

泛型类就是一个类可以实现多个类型的需求,常用的集合List<T> 就是一个泛型类,可以转到定义看到其声明 public class List<T> ,当然进行实例化的时候,必须要指定类型,List<string> names = new List<string>(); 

3.2 泛型接口

泛型接口,就是一个接口 满足多个多个类型的需求。

//声明泛型接口 public interface GenericInterface<T>
{

四、泛型委托

泛型委托与普通的委托相比,它可以适应更多的类型,一般提供了两种泛型委托,一个是Action,无返回值,另一个是Func,带返回值。通常可以自定义泛型委托,如下所示:

public delegate void GenericDelegate <T>(T para);

五、泛型约束

虽然泛型允许我们使用任何类型作为类型参数,但有时候可能需要对类型参数进行一些限制。这时,可以使用泛型约束来实现。泛型约束可以在类、接口或方法的定义中指定,以限制类型参数的类型范围。

C#提供了多种泛型约束,包括:

  • where T : struct:约束类型参数必须是值类型。这确保了类型参数是如intdoublestruct等值类型,而不是引用类型。
  • where T : class:约束类型参数必须是引用类型。这允许你指定类型参数必须是类、接口、委托或数组等引用类型。
  • where T : new():约束类型参数必须有一个无参数的构造函数。这确保了你可以创建该类型的新实例,这在某些需要实例化对象的泛型方法或类中特别有用。
  • where T : BaseClass:约束类型参数必须是BaseClass或其派生类。这允许你指定类型参数必须是某个特定类的子类或该类本身,从而确保类型参数具有某些特定的方法或属性。
  • where T : IInterface:约束类型参数必须实现IInterface接口。这确保了类型参数具有接口中定义的所有方法和属性,这对于确保类型参数符合某种约定或标准非常有用。

在使用泛型约束时,可以在一个泛型定义中指定多个约束。例如,可以同时要求一个类型参数是某个类的子类,并且实现某个接口。但是,这些约束之间必须是逻辑上兼容的,否则编译器会报错。下面是一个使用泛型约束的示例:

        public class GenericList<T> where T : class, IComparable<T>
        {
            private List<T> items = new List<T>();//创建一个泛型列表来存储元素

            public void Add(T item)//添加元素的方法
            {
                items.Add(item);
            }

            public T GetMax()//获取最大值的方法
            {
                if (items.Count == 0)
                    throw new InvalidOperationException("List is empty.");

                T max = items[0];
                foreach (T item in items)
                {
                    if (item.CompareTo(max) > 0)
                        max = item;
                }
                return max;
            }
        }

 在这个示例中,定义了一个泛型类GenericList<T>,它接受一个类型参数T。使用where子句来约束T,要求它必须是引用类型(class),并且必须实现IComparable<T>接口。这样,就可以在GetMax方法中使用CompareTo方法来比较列表中的元素,从而找出最大值。如果类型参数不满足这些约束,编译器将报错。

六、泛型的优点

使用泛型可以带来以下优点:

  • 代码复用:通过定义泛型,我们可以编写一次代码,然后将其用于处理任何类型的数据,从而减少了重复代码的编写。
  • 类型安全:泛型可以在编译时进行类型检查,从而避免了在运行时出现类型错误。
  • 性能:由于泛型在编译时会将类型参数替换为具体的类型,因此可以避免在运行时进行类型检查和装箱/拆箱操作,从而提高了性能。

七、泛型的限制和注意事项

虽然泛型带来了许多优点,但在使用时也需要注意一些限制和注意事项。如,泛型不能用于静态字段或属性,因为静态成员是与类型本身关联的,而不是与类型参数关联的。此外,泛型也不能用于值类型的数组创建,因为值类型在编译时需要确定其大小。另外,虽然泛型可以提高类型安全性,但在某些情况下可能会增加代码的复杂性。因此,在使用泛型时需要根据具体的需求和场景进行权衡和选择。

上一篇:08-Cesium动态处理与圆形闪烁材质相关的属性


下一篇:HTML DOM 教程---获取常规元素方式(2)