泛型是为所存储或使用的一个或多个类型具有占位符(类型形参)的类、结构、接口和方法。泛型集合类可以将类型形参用作其存储的对象类型的占位符;类型形参呈现为其字段的类型和其方法的参数类型。 泛型方法可将其类型形参用作其返回值的类型或用作其形参之一的类型。
泛型的优点包括:代码的可重用性增加,类型安全性提高。
泛型方法
先从一个简单的例子开始
两个数字相加,如果不适用泛型,我们需要使用重载的方式定义方法,比如float,double,decimal,int,都需要单独写一个重载
使用泛型只需要定义一个泛型方法,接受对应的形参就可以完成
internal static class Math{public static T Add<T>(T a, T b) where T:INumber<T> {return a + b;}public static int Add(int a , int b) { return a + b; }public static decimal Add(decimal a, decimal b) { return a + b; }}Console.WriteLine($"1+4={Math.Add<int>(1, 4)}"); Console.WriteLine($"1.1+4.5={Math.Add<decimal>(1.1m, 4.5m)}"); Console.WriteLine($"1+4={Math.Add(1, 4)}"); Console.WriteLine($"1.1+4.5={Math.Add(1.1m, 4.5m)}"); /* * output: 1+4=5 1.1+4.5=5.6 1+4=5 1.1+4.5=5.6 */
泛型类/泛型接口
类和接口也可以是泛型
internal class ClassA: InterfaceA { public ClassA() { }public void ShowMessage(){Console.WriteLine("This is ClassA");} } internal class ClassA<T> : ClassA,InterfaceA {public T Data;public ClassA() { }public ClassA(T arg){Data = arg;}public void ShowMessage() {Console.WriteLine($"This is Generic ClassA, with data:{Data}");} }internal interface InterfaceA {void ShowMessage(); }ClassA a1=new ClassA(); a1.ShowMessage(); ClassA<int> a2=new ClassA<int>(2); a2.ShowMessage(); /** output:This is ClassAThis is Generic ClassA, with data:2*/
下面做一个个人觉得比较实际的泛型使用方式
定义一个通用的返回值泛型类,作为一个实例,应该很多项目里都有类似的结构
public class ReturnResult {public bool Success { get; set; }public string Code { get; set; }public string Message { get; set; }public Exception Exception { get; set; }public ReturnResult(){Success=false;} }public class ReturnResult<T> : ReturnResult {/// <summary>/// default constructor/// </summary>public ReturnResult() : base(){}/// <summary>/// Data/// </summary>public T Data { get; set; } }public class Person {public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"this is person {Name}, age:{Age}";} }public class PersonService { public ReturnResult<Person> GetPerson(string name, int age) {var result = new ReturnResult<Person>();result.Data= new Person() { Name = name, Age = age };result.Success = true;return result;}public ReturnResult<Person> GetPersonFailure(){var result = new ReturnResult<Person>();try {throw new Exception("Exception in GetPersonFailure");} catch (Exception ex) { result.Exception= ex;}return result;} }var _personService=new PersonService(); var getPersonResult1 = _personService.GetPerson("PersonA", 20); var getPersonResult2 = _personService.GetPersonFailure(); Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(getPersonResult1)); Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(getPersonResult2)); /** output:{"Data":{"Name":"PersonA","Age":20},"Success":true,"Code":null,"Message":null,"Exception":null}{"Data":null,"Success":false,"Code":null,"Message":null,"Exception":{"ClassName":"System.Exception","Message":"Exception in GetPersonFailure","Data":null,"InnerException":null,"HelpURL":null,"StackTraceString":" at Learn.CSharp.Generic.PersonService.GetPersonFailure() in D:\\Learn\\C#Learning\\Learn.CSharp.Basic\\Learn.CSharp.Generic\\ReturnResult.cs:line 59","RemoteStackTraceString":null,"RemoteStackIndex":0,"ExceptionMethod":null,"HResult":-2146233088,"Source":"Learn.CSharp.Generic","WatsonBuckets":null}}*/