首页 > 编程笔记 > C#笔记 阅读:9

C#泛型类用法详解(附带实例)

C# 中,泛型类的定义如下:
存取修饰词 class 泛型名称<T>
{
    // 字段、属性和方法
}

如果有两个泛型数据类型,则此类的定义如下:
存取修饰词 class 泛型名称<T, U>
{
    // 字段、属性和方法
}

C#泛型类中的字段

最简单的泛型类,假设只有一个类型参数是定义字段,定义如下:
存取修饰词 class 泛型名称<T>
{
    存取修饰词 T 域名;
}

例如,有一个泛型类与对象的程序如下所示:
DataBank<int> x = new DataBank<int>();
...
public class DataBank<T>
{
    public T db;
}
在程序编译阶段,泛型 T 将会被 int 替换,这时 db 字段将是整型变量 db。

【实例 1】定义泛型类,设定整数然后输出,读者可以从程序认识整个泛型的流程。
DataBank<int> x = new DataBank<int>();
x.db = 5;
Console.WriteLine($"x = {x.db}");

public class DataBank<T>
{
    public T db;
}
执行结果

x = 5


有时候在设计程序时,程序设计师喜欢用下列方式设计第 8 行:
public T? db;

上述是 Microsoft 公司建议的:需要声明的 db 字段可以为 Null,这可以让程序有比较大的弹性,整个设计可以参考下面的实例,这对程序执行结果没有影响。
DataBank<int> x = new DataBank<int>();
x.db = 5;
Console.WriteLine($"x = {x.db}");

public class DataBank<T>
{
    public T? db;
}

【实例 2】泛型类主要可以用于处理不同类型的数据,本实例是定义泛型类,设定整型与字符串型数据然后输出。
DataBank<int> x = new DataBank<int>();
x.db = 5;
Console.WriteLine($"x = {x.db}");
DataBank<string> str = new DataBank<string>();
str.db = "C#";
Console.WriteLine($"str = {str.db}");

public class DataBank<T>
{
    public T? db;
}
执行结果为:

x = 5
str = C#

C#泛型类中的属性

其实在面向对象的程序设计的概念下,为了数据的安全,鼓励程序设计师在类内多多使用属性概念,详情可以参考下列实例。

【实例 3】使用属性概念重新设计实例 2。
DataBank<int> x = new DataBank<int>();
x.Db = 5;
Console.WriteLine($"x = {x.Db}");
DataBank<string> str = new DataBank<string>();
str.Db = "C#";
Console.WriteLine($"str = {str.Db}");

public class DataBank<T>
{
    public T? Db { get; set; }  // Db 属性
}
执行结果与实例 2 相同。

C#泛型类内部的多种数据类型

前面介绍了泛型类内含一种泛型数据类型的情况,我们可以将泛型类扩充为含多笔泛型数据类型,例如字典数据就是配对存在的泛型数据类型,读者可以参考下列实例。

【实例 4】使用泛型创建字典类型的数据。
DataPair<string, int> noodle = new DataPair<string, int>();
noodle.Key = "牛肉面";
noodle.Value = 180;
Console.WriteLine($"{noodle.Key} : {noodle.Value}");

DataPair<string, string> season = new DataPair<string, string>();
season.Key = "春天";
season.Value = "Spring";
Console.WriteLine($"{season.Key} : {season.Value}");

public class DataPair<TKey, TValue>
{
    public TKey? Key { get; set; }
    public TValue? Value { get; set; }
}
执行结果为:

牛肉面 : 180
春天 : Spring


有的 C# 程序设计师会在第 1~3 行(或第 3~8 行)声明与创建类对象 noodle(dict)时,采用以下编码方式:
DataPair<string, int> noodle = new DataPair<string, int>
{
    Key = "牛肉面",
    Value = 180
};
Console.WriteLine($"{noodle.Key} : {noodle.Value}");

DataPair<string, string> season = new DataPair<string, string>
{
    Key = "春天",
    Value = "Spring"
};
Console.WriteLine($"{season.Key} : {season.Value}");

public class DataPair<TKey, TValue>
{
    public TKey? Key { get; set; }
    public TValue? Value { get; set; }
}

C#泛型类内的数组字段

假设泛型内含数组 DataBank,此数组名是 arr,数组大小是 5,则该泛型类的声明方式如下:
public class DataBank<T>
{
    public T[] arr = new T[5];
}

【实例 5】声明含数组字段的泛型类,设定数组元素和输出。
DataBank<int> data = new DataBank<int>();
data.arr[0] = 5;
data.arr[1] = 10;
data.arr[3] = 20;
foreach (var item in data.arr)
    Console.WriteLine(item);

public class DataBank<T>
{
    public T[] arr = new T[5];
}
执行结果为:

5
10
0
20
0

上述我们没有设定 data.arr[2] 和 data.arr[4] 的值,因为数组是整型的,系统使用整型数据的默认值 0,所以可以得到上述结果。

【实例 6】扩充设计实例 5,增加字符串型数据做测试,同时输出索引值对照。
DataBank<int> data = new DataBank<int>();
data.arr[0] = 5;
data.arr[1] = 10;
data.arr[3] = 20;
Console.WriteLine("以下是整数数组");
for (int i = 0; i < data.arr.Length; i++)
    Console.WriteLine($"arr[{i}] = {data.arr[i]}");

DataBank<string> str = new DataBank<string>();
str.arr[0] = "C#";
str.arr[1] = "C++";
str.arr[4] = "Java";
Console.WriteLine("以下是字符串数组");
for (int i = 0; i < str.arr.Length; i++)
    Console.WriteLine($"arr[{i}] = {str.arr[i]}");

public class DataBank<T>
{
    public T[] arr = new T[5];
}
运行结果为:

以下是整数数组
arr[0] = 5
arr[1] = 10
arr[2] = 0
arr[3] = 20
arr[4] = 0
以下是字符串数组
arr[0] = C#
arr[1] = C++
arr[2] =
arr[3] =
arr[4] = Java

对于字符串数组而言,从上述索引 2 和 3 的执行结果可以看到,如果没有设定,那么产生的就是空字符串。

C#泛型类中的方法

1) 泛型方法的参数是泛型

泛型类内可以设计泛型方法,下列将以实例解说。

【实例 7】在泛型类内使用泛型方法 AddItem(),创建泛型数组 arr[ ]。
DataBank<int> x = new DataBank<int>();
x.AddItem(5);
x.AddItem(6);
x.AddItem(7);
x.PrintInfo();
public class DataBank<T>
{
    private T[] arr = new T[5]; // 静态索引变量
    static int index = 0; // 泛型方法,建立数组元素
    public void AddItem(T item)
    {
        arr[index++] = item;
    }
    public void PrintInfo() // 输出泛型数组
    {
        for (int i = 0; i < arr.Length; i++)
            Console.WriteLine($"arr[{i}] = {arr[i]}");
    }
}
执行结果为:

arr[0] = 5
arr[1] = 6
arr[2] = 7
arr[3] = 0
arr[4] = 0

声明泛型类时上述实例第 10 行的泛型方法内容如下:
public void AddItem(T item)
因为第 6 行声明类时已经定义了泛型 <T>,同时第 8 行也定义了泛型 T 是数组,所以 AddItem 右边不用 <T>,编译程序也可以辨识参数 T item 的数据类型。

2) 泛型方法内有一般参数

泛型方法内可以有泛型参数与一般参数并存,详情可以参考下列实例。

【实例 8】更新实例 7,创建泛型数组时,第 1 个参数是索引,第 2 个参数是泛型。
DataBank<int> x = new DataBank<int>();
x.AddItem(0, 5);
x.AddItem(2, 6);
x.AddItem(4, 7);
x.PrintInfo();
public class DataBank<T>
{
    private T[] arr = new T[5];
    public void AddItem(int index, T item) // 泛型方法,创建数组元素
    {
        arr[index] = item;
    }
    public void PrintInfo() // 输出泛型数组
    {
        for (int i = 0; i < arr.Length; i++)
            Console.WriteLine($"arr[{i}] = {arr[i]}");
    }
}
执行结果为:

arr[0] = 5
arr[1] = 0
arr[2] = 6
arr[3] = 0
arr[4] = 7

上述程序第 10 行泛型方法的声明如下:
public void AddItem(int index, T item)
第 1 个参数 int index 是索引,第 2 个参数 T item 是泛型。

3) 泛型方法的数据类型是泛型

如果我们设计的泛型方法需要回传泛型数据,那么可以将泛型方法的数据类型设为泛型,详情可以参考下列实例。

【实例 9】设定泛型方法回传数据为泛型。
DataBank<int> x = new DataBank<int>();
x.AddItem(0, 5);
x.AddItem(2, 6);
x.AddItem(4, 7);
for (int i = 0; i < 5; i++)
    Console.WriteLine($"arr[{i}] = {x.GetArr(i)}");
public class DataBank<T>
{
    private T[] arr = new T[5];
    public void AddItem(int index, T item) // 泛型方法,创建数组元素
    {
        arr[index] = item;
    }
    public T GetArr(int index) // 回传泛型数组特定内容
    {
        if (index >= 0 && index < arr.Length)
            return arr[index];
        else
            return default(T); // 如果超出索引则回传泛型默认值
    }
}
执行结果为:

arr[0] = 5
arr[1] = 0
arr[2] = 6
arr[3] = 0
arr[4] = 7

上述程序第 6 行,泛型类对象 x 调用泛型方法 GetArr(),其所回传的数据就是泛型,所以第 15 行设定泛型方法 GetArr() 的数据类型是泛型 T。

【实例 10】重新设计实例 9,增加测试输出超出泛型索引的结果,同时设定泛型的类型增加?,这是为了可能有 Null 的参数回传。
DataBank<int> x = new DataBank<int>();
x.AddItem(0, 5);
x.AddItem(2, 6);
x.AddItem(4, 7);
for (int i = 0; i < 5; i++)
    Console.WriteLine($"arr[{i}] = {x.GetArr(i)}");
Console.WriteLine($"arr[100] = {x.GetArr(100)}");
public class DataBank<T>
{
    private T[] arr = new T[5];
    public void AddItem(int index, T item) // 泛型方法,创建数组元素
    {
        arr[index] = item;
    }
    public T? GetArr(int index) // 回传泛型数组特定内容
    {
        if (index >= 0 && index < arr.Length)
            return arr[index];
        else
            return default(T); // 如果超出索引则回传泛型默认值
    }
}
执行结果为:

arr[0] = 5
arr[1] = 0
arr[2] = 6
arr[3] = 0
arr[4] = 7
arr[100] = 0

相关文章