解读经典《C#高级编程》泛型 页122-127.章4
前言
本篇继续讲解泛型。上一篇讲解了泛型类的创建。本篇讲解泛型类创建和使用的细节。
泛型类
上篇举了个我产品中用到的例子,本篇的功能可以对照着此案例进行理解。
/// <summary>
/// 单一事务处理服务,用于单表的数据读写事务
/// </summary>
/// <typeparam name="TViewModel"></typeparam>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TDbContext"></typeparam>
public class EFRepository<TViewModel, TEntity, TDbContext> : IDisposable
where TEntity : class,new()
where TViewModel : class,new()
where TDbContext : DbContext,new()
{
private DbContext dbContext;
private DbSet<TEntity> dbSet;
/// <summary>
/// 构造方法
/// </summary>
public EFRepository()
{
dbContext = new TDbContext();
dbSet = dbContext.Set<TEntity>();
}
/// <summary>
/// 根据主键获取单条数据
/// </summary>
/// <param name="keyValues"></param>
/// <returns></returns>
public TViewModel Get(params object[] keyValues)
{
return dbSet.Find(keyValues)
.MapTo<TEntity, TViewModel>();
}
/// <summary>
/// 新增单条数据
/// </summary>
/// <param name="model"></param>
public void Add(TViewModel model)
{
var entity = model.MapTo<TViewModel, TEntity>();
dbSet.Add(entity);
dbContext.SaveChanges();
}
/// <summary>
/// 根据主键删除单条数据
/// </summary>
/// <param name="keyValues"></param>
public void Delete(params object[] keyValues)
{
TEntity entity = dbSet.Find(keyValues);
dbSet.Remove(entity);
dbContext.SaveChanges();
}
}
默认值
T作为泛型类型,有时候会需要取默认值。我们知道,引用类型的默认值是null,数字类型的默认值是0,但泛型类型T既可能是引用类型,也可以是值类型,那默认值就是不定的。怎么解决这个问题?系统提供了default关键字。
var val1 = default(int); //指定类型默认值
var val2 = dafault(T); //泛型类型默认值,dafault(T)在泛型类内部实现上经常用到
约束
在前面的案例中,where语句中的定义就是约束。
where TEntity : class,new()
where TViewModel : class,new()
where TDbContext : DbContext,new()
约束的目的是,限定泛型类型的类型,从而使得泛型类型内部的实现代码可以安全的使用约束条件下的功能方法。
约束类型可以有多种:
where T: class //T必须是类(引用类型)
where T: struct //T必须是结构
where T: Foo //T必须来自基类Foo
where T: IFoo //T必须继承接口IFoo
where T2: T1 //T2必须继承自泛型类型T1
where T: new() //T必须定义一个默认构造函数(构造函数约束只能定义在默认构造函数上,不支持其他重载的构造函数)
where T: Foo, new() //使用逗号,多个约束可叠加
构造函数约束
首先定义构造函数约束的目的,是因为在泛型类内部需要对泛型类型进行初始化,因此要指定约束以保证类型初始化能顺利完成。
而构造函数约束只支持默认构造函数,应该是因为:如果泛型类型定义了多参数构造函数,其构造过程是个难题,初始化的参数如何传入泛型类呢?再引入新的泛型类型?那这个逻辑就死循环了,而且泛型类最终是要通过JIT编译器生成新类的代码的,这会让JIT编译器的实现难度增大。
继承
泛型类的继承还是比较灵活的,可以有以下多种继承方式:
public class MyList1<T> : List<T>
{
//定义泛型类继承自泛型类:泛型类型相同
}
public class MyList2<T> : List<string>
{
//定义泛型类继承自泛型类:基类确定了泛型类型
}
public class MyList3<T> : IEnumerable<T>
{
//定义泛型类继承自泛型接口:泛型类型相同
}
public class MyList4 : List<string>
{
//定义非泛型普通类:基类是明确了泛型类型的泛型类
}
静态成员
泛型类的j静态成员只能在类的一个实例中共享。
public class StaticG<T>
{
public static int index;
}
Main()方法测试:
StaticG<string>.index = 1;
StaticG<int>.index = 2;
Console.WriteLine(StaticG<string>.index); //输出1
Console.WriteLine(StaticG<int>.index); //输出2
回顾前面讲到的原理,这个也是好理解的。因为虽然静态成员定义只在一个类中,但JIT编译器根据不同的T类型编译成的是不同的临时新类。这个例子中,T为int和T为string,会分别被编译成两个新类,那么静态成员分别属于各自的类,数据当然存储为各自不同的两份了。
本篇主要围绕泛型类的定义,讲解定义中的各种特性。下一篇,我们继续讲泛型的更多细节。
觉得文章有意义的话,请动动手指,分享给朋友一起来共同学习进步。
欢迎关注本人如下公众号 “产品技术知与行” ,打造全面的结构化知识库,包括原创文章、免费课程(C#,Java,Js)、技术专题、视野知识、源码下载等内容。
扫描二维码关注
解读经典《C#高级编程》泛型 页122-127.章4的更多相关文章
- C#高级编程笔记之第三章:对象和类型
类和结构的区别 类成员 匿名类型 结构 弱引用 部分类 Object类,其他类都从该类派生而来 扩展方法 3.2 类和结构 类与结构的区别是它们在内存中的存储方式.访问方式(类似存储在堆上的引用类型, ...
- 《Node.js 高级编程》简介与第二章笔记
<Node.js 高级编程> 作者简介 Pedro Teixerra 高产,开源项目程序员 Node 社区活跃成员,Node公司的创始人之一. 10岁开始编程,Visual Basic.C ...
- C#高级编程学习一-----------------第五章泛型
三层架构之泛型应用 概述 1.命名约定 泛型类型以T开头或就是T. 2.泛型类 2.1.创建泛型类
- C#高级编程第9版 第一章 .NET体系结构 读后笔记
.NET的CLR把源代码编译为IL,然后又把IL编译为平台专用代码. IL总是即时编译的,这一点的理解上虽然明白.当用户操作C#开发的软件时,应该是操作已经编译好的程序.那么此时安装在客户机上的程序是 ...
- 20191105 《Spring5高级编程》笔记-第5章
第5章 Spring AOP 面向切面编程(AOP)是面向对象编程(OOP)的补充.AOP通常被称为实施横切关注点的工具.术语横切关注点是指应用程序中无法从应用程序的其余部分分解并且可能导致代码重复和 ...
- 20191105 《Spring5高级编程》笔记-第12章
第12章 使用Spring远程处理 12.4 在Spring中使用JMS 使用面向消息的中间件(通常成为MQ服务器)是另一种支持应用程序间通信的流行方法.消息队列(MQ)服务器的主要优点在于为应用程序 ...
- 20191105 《Spring5高级编程》笔记-第9章
第9章 事务管理 一些名词: 2PC(2 Phase Commit) XA协议 JTS(Java Transaction Service) JCA(Java EE Connector Architec ...
- 20191105 《Spring5高级编程》笔记-第6章
第6章 Spring JDBC支持 Spring官方: 位于Spring Framework Project下. 文档: https://docs.spring.io/spring-framework ...
- 20191103 《Spring5高级编程》笔记-第4章
第4章 详述Spring配置和Spring Boot 4.2 管理bean生命周期 通常,有两个生命周期事件与bean特别相关:post-initialization和pre-destruction. ...
- C#高级编程笔记(11至16章)异步/托管/反射/异常
11.1.2LINQ语句 LINQ查询表达式以from子句开始,以select或者group子句结束.在这两个子句之间可以跟零个或者多个from.let.where.join或者orderby子句. ...
随机推荐
- spring-cloud-Zuul学习(四)【中级】--自定义zuul Filter详解【重新定义spring cloud实践】
实现自定义zuul Filter 方法很简单,只要继承ZuulFilter跟加入到spring IOC容器即可,zuulFilter是一个抽象类,里面包含以下方法需要我们实现: String fi ...
- vue 学习
1.安装vue.js 学习链接: https://cn.vuejs.org/v2/guide/ vue官方文档 vscode 软件框架 https://doc.vux.li/zh-CN/ vux文档
- CSS-默认padding 和 margin
一.h1~h6标签:有默认margin(top,bottom且相同)值,没有默认padding值. 在chrome中:16,15,14,16,17,19; 在firefox中:16,15,14,16, ...
- 了解vue APi
阳光那么好,何必自寻烦恼,过好每一个当下,一万个美丽的未来抵不过一个温暖的现在. 一.Vue.nextTick(): 该api 是在Dom节点更新结束之后执行的一个延时回调.在修改数据之后,立即使用这 ...
- Python练手例子(11)
61.打印出杨辉三角形. #python3.7 from sys import stdout if __name__ == '__main__': a = [] for i in range(10): ...
- Objective-C 优秀文章分享
1. Objective-C Runtime 2.KVO + Block 3.Method Swizzling 和 AOP 实践
- MVC是什么
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑.数据.界面显示分离的方法组织代码 ...
- http请求抓包神器-Fiddler(记录和检查你电脑的所有http通讯)
Fiddler是做什么的,能帮助我们做什么? 1.能够监听http/httpS的流量,可以截获从浏览器或者客户端软件向服务器发送的http/https请求: 2.对截获之后的请求,我们还能够查看请求中 ...
- [Swift]LeetCode15. 三数之和 | 3Sum
Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find ...
- 51Nod-1006 最长公共子序列Lcs
题目链接 Description 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为: abcicba abdkscab ab是两个串的子序列,abc也是,abca ...