泛型方法可以在泛型和非泛型类以及结构和接口中声明。
泛型方法具有类型参数列表和可选的约束。
泛型方法有两个参数列表。
要声明泛型方法,需要:
public void PrintData(S,T)(S p,T t) where S: Person
{
...
}
//:类型参数列表
//(Sp,T t):方法参数列表
//where S: Person:约束子句
void DoStuff(T1 t1,T2 t2)
{
T1 someVar = t1;
T2 otherVar = t2;
}
DoStuff(sVal,iVal);
DoStuff(iVal,lVal);
//:类型实参
编译可以从方法参数中推断类型参数,我们可以省略类型参数和调用中的尖括号。
DoStuff(sVal,iVal);
泛型方法的示例
//非泛型类
class Simple
{
//泛型方法
static public void ReverseAndPrint(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(intArray);//调用方法
Simple.ReverseAndPrint(intArray);//推断类型并调用
Simple.ReverseAndPrint(stringArray);
Simple.ReverseAndPrint(stringArray);
Simple.ReverseAndPrint(doubleArray);
Simple.ReverseAndPrint(doubleArray);
Console.ReadKey();
}
}
和非泛型类一样,泛型类的扩展方法:
static class ExtendHolder
{
public static void Print(this Holder h)
{
T[] vals = h.GetValues();
Console.WriteLine($"{ vals[0] },\t{ vals[1] },\t{ vals[2] }");
}
}
class Holder
{
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(3, 5, 7);
var stringHolder = new Holder("a1", "b2", "c3");
intHolder.Print();
stringHolder.Print();
Console.ReadKey();
}
}
与泛型类相似,泛型结构可以有类型参数和约束。(规则和条件跟泛型类一样)
//泛型结构
struct PieceOfData
{
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(10):构造类型
var intData = new PieceOfData(10);
var stringData = new PieceOfData("Hi there.");
Console.WriteLine($"intData =={ intData.Data }");
Console.WriteLine($"stringData =={ stringData.Data }");
Console.ReadKey();
}
}
输出结果:
intData == 10
stringData == Hi there.
泛型委托和非泛型委托相似,不过类型参数决定了能接受什么样的方法。
delegate R MyDelegate(T value);
//R:返回类型
//:类型参数
//(T value):委托形参
有两个参数列表: 委托形参列表和类型参数列表。
类型参数的范围包括:
//泛型委托
delegate void MyDelegate(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(Simple.PrintString);
mDel += Simple.PrintUpperString;//添加方法
mDel("Hi There.");//调用委托
Console.ReadKey();
}
}
输出结果:
Hi There.
HI THERE.
C# 的 LINQ 特性大量使用了泛型委托。
//泛型委托
public delegate TR Func(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(Simple.PrintString);
Console.WriteLine($"Total:{ myDel(15,13) }");//调用委托
Console.ReadKey();
}
}
输出结果:
Total:28
泛型接口的声明和非泛型接口的声明差不多,但是需要在接口名称之后的尖括号中放置类型参数。
在泛型类型中实现泛型接口。
//泛型接口
interface IMyIfc
{
T ReturnIt(T inValue);
}
//实现泛型接口
class Simple: IMyIfc
{
public S ReturnIt(S inValue)
{
return inValue;
}
}
class Program
{
static void Main(string[] args)
{
var trivInt = new Simple();
var trivString = new Simple();
Console.WriteLine($"{ trivInt.ReturnIt(5) }");
Console.WriteLine($"{ trivString.ReturnIt("Hi there.") }");
Console.ReadKey();
}
}
输出结果:
5
Hi there.
在非泛型类型中实现泛型接口。
//泛型接口
interface IMyIfc
{
T ReturnIt(T inValue);
}
//非泛型类
//
class Simple: IMyIfc, IMyIfc
{
//实现 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.
实现泛型类型接口时,必须保证类型实参的组合不会在类型中产生两个重复的接口。
//泛型接口
interface IMyIfc
{
T ReturnIt(T inValue);
}
//错误:IMyIfc, IMyIfc,
//如果 S 为 int 类型就跟第一个接口重复了
class Simple: IMyIfc, IMyIfc
{
//实现 int 类型接口
public int ReturnIt(int inValue)
{
return inValue;
}
//实现 string 类型接口
public S ReturnIt(S inValue)
{
return inValue;
}
}