前言

本篇继续讲解泛型。上一篇讲解了泛型类的创建。本篇讲解泛型类创建和使用的细节。

泛型类

上篇举了个我产品中用到的例子,本篇的功能可以对照着此案例进行理解。

/// <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的更多相关文章

  1. C#高级编程笔记之第三章:对象和类型

    类和结构的区别 类成员 匿名类型 结构 弱引用 部分类 Object类,其他类都从该类派生而来 扩展方法 3.2 类和结构 类与结构的区别是它们在内存中的存储方式.访问方式(类似存储在堆上的引用类型, ...

  2. 《Node.js 高级编程》简介与第二章笔记

    <Node.js 高级编程> 作者简介 Pedro Teixerra 高产,开源项目程序员 Node 社区活跃成员,Node公司的创始人之一. 10岁开始编程,Visual Basic.C ...

  3. C#高级编程学习一-----------------第五章泛型

    三层架构之泛型应用 概述 1.命名约定 泛型类型以T开头或就是T. 2.泛型类 2.1.创建泛型类

  4. C#高级编程第9版 第一章 .NET体系结构 读后笔记

    .NET的CLR把源代码编译为IL,然后又把IL编译为平台专用代码. IL总是即时编译的,这一点的理解上虽然明白.当用户操作C#开发的软件时,应该是操作已经编译好的程序.那么此时安装在客户机上的程序是 ...

  5. 20191105 《Spring5高级编程》笔记-第5章

    第5章 Spring AOP 面向切面编程(AOP)是面向对象编程(OOP)的补充.AOP通常被称为实施横切关注点的工具.术语横切关注点是指应用程序中无法从应用程序的其余部分分解并且可能导致代码重复和 ...

  6. 20191105 《Spring5高级编程》笔记-第12章

    第12章 使用Spring远程处理 12.4 在Spring中使用JMS 使用面向消息的中间件(通常成为MQ服务器)是另一种支持应用程序间通信的流行方法.消息队列(MQ)服务器的主要优点在于为应用程序 ...

  7. 20191105 《Spring5高级编程》笔记-第9章

    第9章 事务管理 一些名词: 2PC(2 Phase Commit) XA协议 JTS(Java Transaction Service) JCA(Java EE Connector Architec ...

  8. 20191105 《Spring5高级编程》笔记-第6章

    第6章 Spring JDBC支持 Spring官方: 位于Spring Framework Project下. 文档: https://docs.spring.io/spring-framework ...

  9. 20191103 《Spring5高级编程》笔记-第4章

    第4章 详述Spring配置和Spring Boot 4.2 管理bean生命周期 通常,有两个生命周期事件与bean特别相关:post-initialization和pre-destruction. ...

  10. C#高级编程笔记(11至16章)异步/托管/反射/异常

    11.1.2LINQ语句 LINQ查询表达式以from子句开始,以select或者group子句结束.在这两个子句之间可以跟零个或者多个from.let.where.join或者orderby子句. ...

随机推荐

  1. java的3大特性

    java的3大特性 1.继承: * 继承是从已有类得到继承信息创建新类的过程. * 提供继承信息的类被称为父类(超类.基类):得到继承信息的类被称为子类(派生类). * 继承让变化中的软件系统有定的延 ...

  2. DIV滚动条滚动到指定位置(jquery的position()与offset()方法区别小记)

    相对浏览器,将指定div滚到到指定位置,其用法如下 $("html,body").animate({scrollTop: $(obj).offset().top},speed); ...

  3. Java当中的IO二

    1.大文件的读写方法 由于文件很大,我们不能一下子把文件内的所有内容都读取出来,所以只能一段一段的读取 注意:在关闭read()和write()的时候可能会产生IOException,需要对其进行处理 ...

  4. PHP 5.x和PHP 7 Closure不同行为问题

    同样一段闭包代码,PHP 7 ok的,PHP 5.5.11(Windows 开发机器)上却报错,以为是PHP 5 bug,原来是用法不对,记录一下~ 原代码(自己写的框架的路由部分)最初是这样写的: ...

  5. JAVA 热文

    Java技术面试篇 Javase基础面试题(1) Javase基础面试题(2) Javase基础面试题(3) Javase基础面试题(4) Javase基础面试题(5) Javaweb面试题(6) J ...

  6. SUSE12Sp3-Supervisor 守护.net core进程

    1.安装setuptools 将setuptools-0.6c11.tar.gz安装包放到服务器上 tar zxvf setuptools-0.6c11.tar.gz cd setuptools-0. ...

  7. [Swift]LeetCode547. 朋友圈 | Friend Circles

    There are N students in a class. Some of them are friends, while some are not. Their friendship is t ...

  8. 非对称加密技术里面,最近出现了一种奇葩的密钥生成技术,iFace人脸密钥技术

    要说到非对称加密技术啊,得先说说对称加密技术 什么是对称加密技术 对称加密采用了对称密码编码技术,它的特点是文件加密和解密使用相同的密钥加密. 也就是密钥也可以用作解密密钥,这种方法在密码学中叫做对称 ...

  9. Python基础综合运用——搭建名片管理系统

    综合应用 —— 名片管理系统 目标 综合应用已经学习过的知识点: 变量 流程控制 函数 模块 开发 名片管理系统 系统需求 程序启动,显示名片管理系统欢迎界面,并显示功能菜单 ************ ...

  10. 性能调优之Transformation

    优化之Aggregator组件 优化之Custom组件 优化之Joiner组件 优化之Lookup组件 优化之Normalizer组件 优化之Sequence Generator组件 优化之Sorte ...