大多数人,都低估了编程学习的难度,而高估了自己的学习能力和毅力。
当前系列: C#语法 修改讲义

复习:J&C:泛型


泛型

真泛型

所以能提高性能:(不同的泛型参数)编译时生成(不同的类),避免装箱/拆箱等类型转换 (对比:Java的泛型擦除

class Student<T> 
class Student

是可以共存的。

语法区别

泛型方法

static T grow<T>(T year)    //泛型参数的声明在方法名后面
{
    return default(T);
}

类型约束

使用where关键字和冒号(:)

internal class Generic<T> where T : Person  /*只能是Person及其子类*/
internal class Generic<T> where T : ISort   /*只能是ISort及其实现*/

还有额外的约束

internal class Generic<T> where T : struct  /*只能是值类型,由struct定义*/
internal class Generic<T> where T : class   /*只能是引用类型,由class定义*/
internal class Generic<T> where T : new()   /*必须包含一个公共的无参构造函数,可以new()*/
为同一个Type parameter定义多个(不冲突的)约束,用逗号分割:
    class MimicStack<T, TKey>
        //where T : class, struct  冲突了,不行
        where T : ILearn, new()
        where TKey: new()

且new()/struct/class要放在最后。

默认值default()

可以获取某个类型的默认值

array[0] = default(T);

尤其当不知道T具体为何类型时有用。

using别名

当泛型类变得冗长的时候奇巧淫技

using StudentMC = Student<Major<string>, Score<Major<string>, double>>;
StudentMC student = new StudentMC();


变体

复习:泛型类还不是“类”。相同的泛型类,使用不同的类型参数,就是不同的类。

//Major<string> minor = new Major<int>();    报错

即使类型参数之间有继承关系也不行:

Major<Person> minor = new Major<Student>();
但是,为了让被定义的泛型接口和委托,可以有更广泛的应用。从.NET4.0开始,可以:
  • 声明(不是使用)
  • 泛型接口委托(不能是其他)时(泛型可以用于委托)
  • 可以在类型参数添加(in或out)“变体”的指示

具体来说:

准确描述:一个类型参数声明了协变out(或逆变in)的泛型接口,用父类(或子类)做类型参数时,可以接受子类(或父类)做类型参数的实例。

理解(帮助记忆)in和out:


泛型参数用于 比如:
所以
in
输入
IComparable<T>,T由外部传入,在方法内部使用
内部使用T的父类是OK的
out
输出
IEnumerable<T>,T最终是会输出到外部,供外部使用的
外部使用T的子类是OK的

interface ISort<out T>
{
    public T GetMax();

//--------------------------------

class BubbleSort<T> : ISort<T>
{
    public T GetMax()
    {
        return default(T);

//--------------------------------

ISort<Person> iP = new BubbleSort<Student>();
Person person = iP.GetMax();
//说明:传入和返回的都是Student,能够被Person“装”(引用)
interface ISort<in T> where T : Person
{
    public int Compare(T x, T y);

//----------------------------------

class BubbleSort<T> : ISort<T> where T : Person
{
    public int Compare(T x, T y)
    {
        Console.WriteLine(x.Name);    //只要是Person的子类,一定有Name属性的

//----------------------------------

ISort<Student> iP = new BubbleSort<Person>();
//按声明传Student
iP.Compare(new Student(), new Student());
总的来说,就是不让后续的调用出现“类型不兼容”的问题,类似于讲继承多态时为什么只能是“父类变量装子类对象”……



可空(Nullable)类型

复习:值类型变量不能被赋值为null

但有时候需要一个值类型变量的值为null:

  • 方便和数据库交互
  • 比如性别(IsMale),通常用bool值,但可以有三个值:男、女和“没填写”
在值类型后面加一个问号(?),就可以声明一个该值类型对象的可空类型,可空类型可以为null值
            int? i = 18;
            int j = i.Value;
            i = null;
            Console.WriteLine(i.HasValue);

演示:F12查看源代码

public struct Nullable<T> where T : struct

所以本质上,int?是Nullable<int>:

int? age = new Nullable<int>(32);

根据源代码演示/复习:构造函数、只读属性、类型转换重载、override Object方法……


null运算

NullReferenceException是最常见的异常。

演示:形成过程

class Student
{
    public double[] Scores { get; set; }
new Student().Scores[0] = 98.5;
为了避免抛出这种异常,以前我们不得不在代码中加上大量的null check语句:
if (Scores == null)
{
    Scores = new double[10];
}
else

null值替代运算符 ??

不为null值时,返回原值;为null值时,返回 ?? 后替代值

    SQL.Teacher = SQL.Teacher ?? new Teacher();

等同于:

    if (SQL.Teacher == null)
    {
        SQL.Teacher = new Teacher();
    }

null条件运算符 ?. 和 ?[]

只有 . 或者 [] 前面的变量不为null值的时候,才进行取值;否则返回null值。

    string name = SQL.Teacher?.Name;

等同于:

    string name = null;
    if (SQL.Teacher.Name != null)
    {
        name = SQL.Teacher.Name;
    }/*else name 仍然是null*/


C#7.0之后:引用可空类型

可空类型后面也可以加?表示它是可空的。

public string? Name { get; set; }


如果没有?,不是可空的,VS会给警告。去除警告的方式是添加针对该属性的构造函数(#体会#:为什么这么设计?)

如果在调用时可以确认某可空类型属性不为空,可以加!去掉警告:

Console.WriteLine(new Student().Name!.Length);

如果觉得不需要这种可空引用类型检查,可以在project配置文件中全局disabled:

会在.proj中添加/更改:


  <PropertyGroup>
    <Nullable>enable</Nullable>
  </PropertyGroup>



作业

  1. 用代码演示泛型接口的协变/逆变
  2. #试一试#@想一想@:这行代码啥意思:
    Console.WriteLine(SQL.Teacher?.Name ?? "course SQL has no teacher");

其他见:J&C:泛型:作用 / 具象化 / 约束 / 继承

学习笔记
源栈学历
键盘敲烂,月薪过万作业不做,等于没学

作业

觉得很 ,不要忘记分享哟!

任何问题,都可以直接加 QQ群:273534701

在当前系列 C#语法 中继续学习:

上一课: C#:异常

多快好省!前端后端,线上线下,名师精讲

  • 先学习,后付费;
  • 不满意,不要钱。
  • 编程培训班,我就选源栈

更多了解 加:

QQ群:273534701

答疑解惑,远程debug……

B站 源栈-小九 的直播间

写代码要保持微笑 (๑•̀ㅂ•́)و✧

公众号:源栈一起帮

二维码