泛型(Generic) 允许您延迟编写类或方法中的编程元素的数据类型的规范,直到实际在程序中使用它的时候。换句话说,泛型允许您编写一个可以与任何数据类型一起工作的类或方法。
C# 允许您使用类型参数(type parameter)而不使用特定数据类型来定义泛型类、接口、抽象类、字段、方法、静态方法、属性、事件、委托和运算符。 类型参数是创建泛型类型实例时指定的特定类型的占位符。
泛型类型是通过在类型名称后的尖括号中指定类型参数来声明的,例如 TypeName
下面这个简单的实例将有助于您理解这个概念:
泛型类是使用类名后尖括号中的类型参数定义的。 下面定义了一个泛型类。
class Program
{
static void Main(string[] args)
{
var my = new MyFloatList<int>();
my[0] = 1;
my[1] = 2;
my[2] = 3;
my[3] = 4;
for (int i = 0; i < 4; i++)
{
//注意这边是string了
Console.Write(my[i.ToString()] + ",");
}
}
}
public class MyFloatList<T>
{
private T[] list = new T[4]; //当 T 是 int的时候这边就相当于 int[] list = new int[]了。
public T this[int index] //
{
get => list[index];
set => list[index] = value;
}
public T this[string index]
{
get
{
var i = Convert.ToInt32(index);
return list[i];
}
set
{
var i = Convert.ToInt32(index);
list[i] = value;
}
}
}
当它运行的时候它会输出
1,2,3,4,
代码的表现就是MyFloatList
类里面的T会变替换成 int类型,
我们也可以把类型参数换成 string如下
static void Main(string[] args)
{
var my = new MyFloatList<string>(); //可以看到 上面的int变成了 string。 当然也可以是其它类型了如 float decimal 等
my[0] = "a";
my[1] = "b";
my[2] = "c";
my[3] = "d";
for (int i = 0; i < 4; i++)
{
//注意这边是string了
Console.Write(my[i.ToString()] + ",");
}
}
当它运行的时候它会输出
a,b,c,d,
代码的表现就是MyFloatList
类里面的T会变替换成 string类型,
KeyValuePair 是 一个系统类。我们看到它使用了两个类型参数,并且它的类型参数名不在是T了,变成了 TKey,TValue。
class KeyValuePair<TKey, TValue>
{
public TKey Key { get; set; }
public TValue Value { get; set; }
}
再来看其它的一个例子, 在 Restful的Api当中,我们有时候会返回一个特定的格式。我们就可以把返回类型 定义在泛型类型参数里。
class Program
{
static void Main(string[] args)
{
var vm = new ResultVm<DateTime>(DateTime.Now);
Console.WriteLine(vm.PlayLoad);
}
}
public class ResultVm<T1>
{
public ResultVm(T1 playLoad) //构造器这边不需要<>这个东西
{
this.PlayLoad = playLoad;
}
public T1 PlayLoad { get; set; }
public List<string> ErrorMessages { get; set; }
}
一个方法里面的参数有类型参数,或者返回类型是类型参数的话,我们称它为泛型方法。
class MyList<T>
{
private T[] _data = new T[10];
public void AddOrUpdate(int index, T item)
{
if(index >= 0 && index < 10)
_data[index] = item;
}
public T GetData(int index)
{
if(index >= 0 && index < 10)
return _data[index];
else
return default(T);
}
}
上面的 AddorUpdate() 和 GetData() 方法是泛型方法。 item 参数的实际数据类型将在实例化 DataStore
class Program
{
static void Main(string[] args)
{
var names = new MyList<string>();
names.AddOrUpdate(0, "Ma");
names.AddOrUpdate(1, "Lema");
names.AddOrUpdate(2, ".net");
var empIds = new MyList<int>();
empIds.AddOrUpdate(0, 50);
empIds.AddOrUpdate(1, 65);
empIds.AddOrUpdate(2, 89);
var id = empIds.GetData(0);
}
}
泛型参数类型可以与带或不带非泛型参数和返回类型的多个参数一起使用。 以下是有效的泛型方法重载。
public void AddOrUpdate(int index, T data) { }
public void AddOrUpdate(T data1, T data2) { }
public void AddOrUpdate<U>(T data1, U data2) { }
public void AddOrUpdate(T data) { }
非泛型类可以通过在带有方法名称的尖括号中指定类型参数来包含泛型方法,如下所示。
class Printer
{
public void Print<T>(T data)
{
// var t = typeof(T); //通过这个也可以获取到运行时的类型
Console.WriteLine(data);
}
public static void Print2<T>(T data)
{
Console.WriteLine(data);
}
}
class Program
{
static void Main(string[] args)
{
var printer = new Printer();
printer.Print<int>(100);
printer.Print(200); // 可以做到自动类型推断
printer.Print<string>("Hello");
Printer.Print2("World!"); // 可以做到自动类型推断 string
}
}
静态类,和静态方法都是支持泛型的