C#:泛型(Generic)
前言:
此系列都为个人对C#的回顾,属于个人理解,新司机可参考、求老司机指点。如果有什么问题或不同见解,欢迎大家与我沟通!
目录:
- 泛型是什么
通过“参数化类型(不指定类型)”来实现在同一份代码上操作多种数据类型。
在声明时不指定类型,编译后查看IL代码可看到生成为占位符“`1”(1表示只有一个泛型参数,两个就是`2,以此类推) ,调用时会生成不同类型的方法,也就是最终还是会生成多个方法!
- 泛型的好处及用途
我们来假设一个场景:需要在控制台输出各种类型(可能不太形象,个人感觉ORM框架中数据保存那块很形象)。
在泛型没出现之前,我们基本都是采用以下这种方式来实现:
这个时候该有人说了这样写以后扩展太麻烦,咱可以采用object,毕竟object是所有类型的基类,也就是以下这种:
确实,类型不明确的地方可以使用object类型,一样可以达到目的。不过这种办法会引起:
1.使用object导致的类型安全问题
2.拆箱装箱导致性能下降
泛型的出现就是为了解决以上几种情况的问题,上面那个例子可以改为:
综其上述,泛型的好处有:
1.泛型采用延迟声明思想,将“参数化类型”将类型抽象化,从而实现更为灵活的复用。
2.泛型赋予了代码更强的类型安全,更高的效率,更清晰的约束。
泛型的用途很广泛,在.net各处都有体现,比如常见的List<T>、IEnumerable<T>、ICollection<T>等等。个人觉得说起泛型就应该说说委托。。。
例如:Linq中的方法都是采用的泛型加委托
- 如何声明使用泛型
泛型类:
/// <summary>
/// 这就是一个泛型类,是不是很简单
/// </summary>
/// <typeparam name="T">类型参数</typeparam>
public class Generic<T>
{
/// <summary>
/// 泛型方法
/// </summary>
/// <param name="type">泛型参数,根据类指定</param>
/// <returns></returns>
public T OutPut(T type)
{
Console.WriteLine(type.GetType());
return default(T);
}
} public class Test
{
Generic<int> genericInt;
Generic<string> genericString;
public Test()
{
//泛型类调用1
genericInt = new Generic<int>();
genericInt.OutPut();
//泛型类调用2
genericString = new Generic<string>();
genericString.OutPut("我就是泛型方法,不过我的参数类型是根据类来决定的,我的兄弟会在下面粗现~~");
}
}
泛型方法:
public class Generic<T>
{
/// <summary>
/// 泛型方法
/// </summary>
/// <param name="type">泛型参数,根据类指定</param>
/// <returns></returns>
public T OutPut(T type)
{
Console.WriteLine(type.GetType());
return default(T);//default(T)返回类型默认值
} /// <summary>
/// 泛型方法,注意看,我与上面不同哦!调用也不同哦!
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="tresult"></param>
/// <returns></returns>
public TResult GenericAction<TResult>(TResult tresult)
{
Console.WriteLine(tresult.GetType());
return default(TResult);
}
/// <summary>
/// 可以随便写,类上面也一样~~~~~
/// </summary>
public TResult GenericAction<TResult, LResult, SResult>(TResult tresult,LResult lresult,SResult sresult)
{
Console.WriteLine(tresult.GetType());
return default(TResult);
}
} public class Test
{
Generic<int> genericInt;
Generic<string> genericString;
Generic<DateTime> genericDateTime;
public Test()
{
//泛型类调用1
genericInt = new Generic<int>();
genericInt.OutPut();
//泛型类调用2
genericString = new Generic<string>();
genericString.OutPut("我就是泛型方法,不过我的参数类型是根据类来决定的,我的兄弟会在下面粗现~~");
//泛型方法调用3
genericDateTime = new Generic<DateTime>();
genericDateTime.GenericAction<string>("我的最终输出结果是根据方法的类型参数决定的,跟类无关!");
}
}
}
泛型接口:
//泛型接口
public interface IGeneric<T>
{
}
//普通类继承泛型接口,需要指定基类泛型类型
public class Generic : IGeneric<string>
{
}
//泛型类继承泛型接口
public class Test<T> : IGeneric<int>
{
}
//泛型类继承泛型接口,并运用子类的泛型类型
public class Test1<T> : IGeneric<T>
{
}
//随便怎么玩都可以~~~~~~~其他的大家都可以试试
泛型委托:个人觉得泛型委托是个重点,在.net中处处体现了这点,比如我上面所说到的Linq方法。如果有对委托不熟悉的,我会在后面写一篇关于对委托的介绍。
1.首先我们先自定义一个泛型委托
class Program
{
//这里定义了一个无参有返回值的泛型的委托
public delegate T CustomDelegate<T>();
//这里定义了一个有参有返回值的泛型的委托
public delegate T CustomDelegate1<T>(T type); static void Main(string[] args)
{
//声明这个无参有返回值泛型委托
CustomDelegate<int> customDelegate = new CustomDelegate<int>(() => { return ; });//() => { return 1; }匿名方法
//调用这个泛型委托
customDelegate.Invoke(); //声明这个有参有返回值泛型委托
CustomDelegate1<string> customDelegate1 = new CustomDelegate1<string>((i) => { return i; });
customDelegate1.Invoke("有参有返回值"); //其他的无参无返回值,有参无返回值大家都可以试下,也可以尝试定义成多个参数的委托试试!!!
}
}
2.微软在.net为我们封装好的三个泛型委托,为了简化咱们的工作量,不用自定义委托
class Program
{
static void Main(string[] args)
{
//1.Func
Func<string> func = new Func<string>(() => { return default(string); }); //2.Action
Action<string> action = new Action<string>((i) => { }); //3.Predicate
Predicate<bool> pre = new Predicate<bool>((i) => { return true; }); //这三个泛型委托用处不同.
//比如Func就在Linq方法中经常用到,在F12进去之后可以看到类型参数上带有out修饰符
//Action,在F12进去之后可以看到类型参数上带有in修饰符
//in 与 out 则就是我们后面要说的逆变与协变了
//Predicate,则就是一个条件判断委托了
//具体的应用场景大家可以想象下
}
}
泛型约束:
在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制。如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误。这些限制称为约束。约束是使用 where 上下文关键字指定的。下表列出了六种类型的约束:
约束 | 说明 |
---|---|
T:结构 |
类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。有关更多信息,请参见使用可空类型(C# 编程指南)。 |
T:类 |
类型参数必须是引用类型,包括任何类、接口、委托或数组类型。 |
T:new() |
类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。 |
T:<基类名> |
类型参数必须是指定的基类或派生自指定的基类。 |
T:<接口名称> |
类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。 |
T:U |
为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束。 |
1.T:结构
2.T:类
3.T:new()
4.T:<基类名>
5.T:<接口名称>
6.T:U
扩展:
让我们通过泛型与泛型委托来扩展一个IEnumerable方法(需要了解C#扩展方法)
public static class Extends //静态类
{
/// <summary>
/// 只要有一个满足于predicate条件就返回true
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="tsource"></param>
/// <param name="predicate"></param>
/// <returns></returns>
public static bool MaxBool<TSource>(this IEnumerable<TSource> tsource, Func<TSource, bool> predicate)
{
foreach (var item in tsource)
{
if (predicate(item))
{
return true;
}
}
return false;
}
} static void Main(string[] args)
{
//为什么List能使用MaxBool()我就不用说了吧。。。。。
List<int> listA = new List<int>() { , , };
bool trueOrFalse = listA.MaxBool(item => item > );
}
这里只是一个简单的例子,大家可以试试对其他的进行扩展!
C#:泛型(Generic)的更多相关文章
- Java - 泛型 ( Generic )
Java - 泛型 ( Generic ) > 泛型的特点 > 解决元素存储的安全性问题 > 解决获取数据元素时,需要类型强转的问题 ...
- Java之集合初探(二)Iterator(迭代器),collections,打包/解包(装箱拆箱),泛型(Generic),comparable接口
Iterator(迭代器) 所有实现了Collection接口的容器都有一个iterator方法, 用来返回一个实现了Iterator接口的对象 Iterator对象称作迭代器, 用来方便的实现对容器 ...
- 谈一谈从 Delphi 2009 之后就支援的重要功能 – 泛型 (Generic)
前言 在C++的语言基础当中,除了物件导向.事件驱动的概念之外,模版设计(Template)也是非常重要的一环.然而,C++的开发人员能够善用模版设计的并不多.模版设计这个好物,一般还有一个名称,就是 ...
- JAVA中的泛型(Generic)
Java泛型(Generic)简介 泛型是jdk1.5版本以后推出来的,表示类型参数化,让java能更具有动态性一些,让类型能变成参数传递. 要我自己感觉的话,泛型本身没啥用,跟反射在一起用,就体现出 ...
- Dephi泛型generic的应用
Dephi泛型generic的应用 泛型在C++, C#中已有广泛应用,Delphi自2009版本也引入泛型,典型的应用如TList,TDictionary.如果你熟悉C#,其用法十分类似. 比如 ...
- Java基础之Comparable接口, Collections类,Iterator接口,泛型(Generic)
一.Comparable接口, Collections类 List的常用算法: sort(List); 排序,如果需要对自定义的类进行排序, 那就必须要让其实现Comparable接口, 实现比较两个 ...
- Java自学-集合框架 泛型Generic
ArrayList上使用泛型 步骤 1 : 泛型 Generic 不指定泛型的容器,可以存放任何类型的元素 指定了泛型的容器,只能存放指定类型的元素以及其子类 package property; pu ...
- C#泛型(Generic)
一.什么是泛型 泛型(Generic)是C#语言2.0.通用语言运行时(CLR)2.0..NET Framework2.0推出来的新特性. 泛型为.NET框架引入类型参数(Type Parameter ...
- .NET知识梳理——1.泛型Generic
1. 泛型Generic 1.1 引入泛型:延迟声明 泛型方法声明时,并未写死类型,在调用的时候再指定类型. 延迟声明:推迟一切可以推迟的. 1.2 如何声明和使用泛型 泛 ...
- C# 泛型Generic
泛型(Generic),是将不确定的类型预先定义下来的一种C#高级语法,我们在使用一个类,接口或者方法前,不知道用户将来传什么类型,或者我们写的类,接口或方法相同的代码可以服务不同的类型,就可以定义为 ...
随机推荐
- Linq语法学习
关键词: select from where in into join on equals orderby descending DefaultIfEmpty() thenby submitChang ...
- ThreadLocal 源码剖析
ThreadLocal是Java语言提供的用于支持线程局部变量的类.所谓的线程局部变量,就是仅仅只能被本线程访问,不能在线程之间进行共享访问的变量(每个线程一个拷贝).在各个Java web的各种框架 ...
- getopt,getoptlong学习
getopt和getoptlong被用来解析命令行参数. 一.getopt #include <unistd.h> extern char *optarg; extern i ...
- windows中,端口查看&关闭进程及Kill使用
测试过程中遇到的问题,杂记一: 1.netstat -ano | findstr "8001" 查看端口8001被哪个进程占用:由下图可以看出,被进程为3736的占用 2.查 ...
- HDOJ 1008. Elevator 简单模拟水题
Elevator Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Su ...
- scheduletask任务调度(2间隔时间)
Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("myTrigger", "myTriggerGr ...
- 图片下方出现多3px的原因及解决方法
产生原因:主要是因为图片的垂直对齐方式vertical-align引发的,默认值是baseline,默认为此值时图片下方就会多出3px. 解决方案: 1.将图片的垂直对齐方式vertical-alig ...
- [LeetCode] Palindrome Linked List 回文链表
Given a singly linked list, determine if it is a palindrome. Follow up: Could you do it in O(n) time ...
- [LeetCode] Majority Element 求众数
Given an array of size n, find the majority element. The majority element is the element that appear ...
- sqlite3的图片的(二进制数据)存取操作
sqlite3的图片的(二进制数据)存取操作 前言 上篇介绍了sqlite3的一些常用插入操作方法和注意事项,在实际项目中遇到了图片缓存的问题,由于服务器不是很稳定,且受到外界环境的干扰(例如断电 ...