一、泛型方法
泛型方法可以在泛型和非泛型类以及结构和接口中声明。
1、声明泛型方法
泛型方法具有类型参数列表和可选的约束。
-
泛型方法有两个参数列表。
- 封闭在圆括号内的方法参数列表。
- 封闭在尖括号内的类型参数列表。
-
要声明泛型方法,需要:
- 在方法名称之后和方法参数列表之前放置类型参数列表;
- 在方法参数列表后放置可选的约束子句。
public void PrintData(S,T)(S p,T t) where S: Person
{
...
}
//<S,T>:类型参数列表
//(Sp,T t):方法参数列表
//where S: Person:约束子句
2、调用泛型方法
void DoStuff<T1,T2>(T1 t1,T2 t2)
{
T1 someVar = t1;
T2 otherVar = t2;
}
DoStuff<short,int>(sVal,iVal);
DoStuff<int,short>(iVal,lVal);
//<short,int>:类型实参
3、推断类型
编译可以从方法参数中推断类型参数,我们可以省略类型参数和调用中的尖括号。
DoStuff(sVal,iVal);
泛型方法的示例
//非泛型类
class Simple
{
//泛型方法
static public void ReverseAndPrint<T>(T[] arr)
{
Array.Reverse(arr);
//使用类型实参 T
foreach (T item in arr)
Console.Write($"{item.ToString() },");
Console.WriteLine("");
}
}
class Program
{
static void Main(string[] args)
{
//创建各种类型的数组
var intArray = new int[] { 3, 5, 7, 9, 11 };
var stringArray = new string[] { "first", "second", "third" };
var doubleArray = new double[] { 3.567, 7.891, 2.345 };
Simple.ReverseAndPrint<int>(intArray);//调用方法
Simple.ReverseAndPrint(intArray);//推断类型并调用
Simple.ReverseAndPrint<string>(stringArray);
Simple.ReverseAndPrint(stringArray);
Simple.ReverseAndPrint<double>(doubleArray);
Simple.ReverseAndPrint(doubleArray);
Console.ReadKey();
}
}
二、扩展方法和泛型类
和非泛型类一样,泛型类的扩展方法:
- 必须声明为 static;
- 必须是静态类的成员;
- 第一个参数类型中必须有关键字 this,后面是扩展的泛型类的名字。
static class ExtendHolder
{
public static void Print<T>(this Holder<T> h)
{
T[] vals = h.GetValues();
Console.WriteLine($"{ vals[0] },\t{ vals[1] },\t{ vals[2] }");
}
}
class Holder<T>
{
T[] Vals = new T[3];
public Holder(T v0,T v1,T v2)
{
Vals[0] = v0;Vals[1] = v1;Vals[2] = v2;
}
public T[] GetValues() { return Vals; }
}
class Program
{
static void Main(string[] args)
{
var intHolder = new Holder<int>(3, 5, 7);
var stringHolder = new Holder<string>("a1", "b2", "c3");
intHolder.Print();
stringHolder.Print();
Console.ReadKey();
}
}
三、泛型结构
与泛型类相似,泛型结构可以有类型参数和约束。(规则和条件跟泛型类一样)
//泛型结构
struct PieceOfData<T>
{
public PieceOfData(T value){ _data = value; }
private T _data;
public T Data
{
get { return _data; }
set { _data = value; }
}
}
class Program
{
static void Main(string[] args)
{
//PieceOfData<int>(10):构造类型
var intData = new PieceOfData<int>(10);
var stringData = new PieceOfData<string>("Hi there.");
Console.WriteLine($"intData =={ intData.Data }");
Console.WriteLine($"stringData =={ stringData.Data }");
Console.ReadKey();
}
}
输出结果:
intData == 10
stringData == Hi there.
四、泛型委托
1、泛型委托
泛型委托和非泛型委托相似,不过类型参数决定了能接受什么样的方法。
delegate R MyDelegate<T,R>(T value);
//R:返回类型
//<T,R>:类型参数
//(T value):委托形参
有两个参数列表: 委托形参列表和类型参数列表。
类型参数的范围包括:
- 返回类型;
- 形参列表;
- 约束子句。
//泛型委托
delegate void MyDelegate<T>(T value);
class Simple
{
//方法匹配委托
static public void PrintString(string s)
{
Console.WriteLine(s);
}
static public void PrintUpperString(string s)
{
Console.WriteLine($"{s.ToUpper()}");
}
}
class Program
{
static void Main(string[] args)
{
//创建委托的实例
var mDel = new MyDelegate<string>(Simple.PrintString);
mDel += Simple.PrintUpperString;//添加方法
mDel("Hi There.");//调用委托
Console.ReadKey();
}
}
输出结果:
Hi There.
HI THERE.
2、另一个泛型委托示例
C# 的 LINQ 特性大量使用了泛型委托。
//泛型委托
public delegate TR Func<T1, T2, TR>(T1 P1, T2 P2);
class Simple
{
//方法匹配委托
static public string PrintString(int p1, int p2)
{
int total = p1 + p2;
return total.ToString();
}
}
class Program
{
static void Main(string[] args)
{
//创建委托实例
var myDel = new Func<int, int, string>(Simple.PrintString);
Console.WriteLine($"Total:{ myDel(15,13) }");//调用委托
Console.ReadKey();
}
}
输出结果:
Total:28
五、泛型接口
1、泛型接口
泛型接口的声明和非泛型接口的声明差不多,但是需要在接口名称之后的尖括号中放置类型参数。
在泛型类型中实现泛型接口。
//泛型接口
interface IMyIfc<T>
{
T ReturnIt(T inValue);
}
//实现泛型接口
class Simple<S>: IMyIfc<S>
{
public S ReturnIt(S inValue)
{
return inValue;
}
}
class Program
{
static void Main(string[] args)
{
var trivInt = new Simple<int>();
var trivString = new Simple<string>();
Console.WriteLine($"{ trivInt.ReturnIt(5) }");
Console.WriteLine($"{ trivString.ReturnIt("Hi there.") }");
Console.ReadKey();
}
}
输出结果:
5
Hi there.
2、使用泛型接口的示例
在非泛型类型中实现泛型接口。
//泛型接口
interface IMyIfc<T>
{
T ReturnIt(T inValue);
}
//非泛型类
//
class Simple: IMyIfc<int>, IMyIfc<string>
{
//实现 int 类型接口
public int ReturnIt(int inValue)
{
return inValue;
}
//实现 string 类型接口
public string ReturnIt(string inValue)
{
return inValue;
}
}
class Program
{
static void Main(string[] args)
{
Simple trivial = new Simple();
Console.WriteLine($"{ trivial.ReturnIt(5) }");
Console.WriteLine($"{ trivial.ReturnIt("Hi there.") }");
Console.ReadKey();
}
}
输出结果:
5
Hi there.
3、泛型接口的实现必须唯一
实现泛型类型接口时,必须保证类型实参的组合不会在类型中产生两个重复的接口。
//泛型接口
interface IMyIfc<T>
{
T ReturnIt(T inValue);
}
//错误:IMyIfc<int>, IMyIfc<S>,
//如果 S 为 int 类型就跟第一个接口重复了
class Simple<S>: IMyIfc<int>, IMyIfc<S>
{
//实现 int 类型接口
public int ReturnIt(int inValue)
{
return inValue;
}
//实现 string 类型接口
public S ReturnIt(S inValue)
{
return inValue;
}
}