目录
[1. 一个类同时实现多个接口](#1. 一个类同时实现多个接口)
[2. 接口继承(接口多继承)](#2. 接口继承(接口多继承))
[3. 抽象类 vs 接口 异同](#3. 抽象类 vs 接口 异同)
[1. 泛型概念](#1. 泛型概念)
[三、泛型效率(Stopwatch 测速)](#三、泛型效率(Stopwatch 测速))
[四、泛型接口 & 泛型类](#四、泛型接口 & 泛型类)
[1. 泛型接口定义](#1. 泛型接口定义)
[2. 两种实现方式](#2. 两种实现方式)
[五、泛型约束 where](#五、泛型约束 where)
一、多接口
1. 一个类同时实现多个接口
- 多个接口成员重名、类型相同:只实现一次即可。
- 多个接口成员同名但返回 / 字段类型不同 :必须显式接口实现 ,格式:
接口名.成员名,显式实现不能加访问修饰符(默认私有)。
csharp
运行
cs
interface IA
{
int A { get; set; }
string B { get; set; }
string C { get; set; }
void F1();
}
interface IB
{
string B { get; set; }
int C { get; set; }
void F1(int a);
}
class Test : IA, IB
{
public int A { get; set; }
public string B { get; set; }
//显式实现IA的C
string IA.C { get; set; }
//显式实现IB的C
int IB.C { get; set; }
public void F1() { }
public void F1(int a) { }
}
使用:想要调用 IA 的 C,变量声明为
IA;调用 IB 的 C,变量声明为IB。
cs
IA t1 = new Test();
t1.C = "11";
IB i1 = new Test();
i1.C = 10;
2. 接口继承(接口多继承)
接口可以继承另一个 / 多个接口;子类实现派生接口时,必须实现所有父接口全部成员。
cs
interface IC { string B { get; set; } }
interface IQ : IC { int C { get; set; } }
class Test1 : IQ
{
public int C { get; set; }
public string B { get; set; }
}
3. 抽象类 vs 接口 异同
相同点
- 都不能直接实例化
- 都能包含未实现成员,由子类去实现
不同点
- 抽象类可包含普通实现方法;接口所有成员默认抽象,不能写方法体
- 一个类只能继承一个抽象类 ;可以实现多个接口
- 抽象类重写用
override;接口实现直接写 public 成员 - 抽象类成员可以加访问修饰符;接口成员默认 public,不能手动修饰
- 抽象类可以定义字段;接口不能定义实例字段,只能属性、方法
二、泛型方法
1. 泛型概念
泛型:延迟确定数据类型 ,方法定义时不固定参数 / 返回值类型,调用时传入具体类型<T>,一套代码适配多种数据类型。语法:方法名<泛型标识>(参数),常用 T、T1、T2 做泛型符号。
cs
//单泛型
static T Test<T>(T a)
{
return a;
}
//调用,显式指定类型
Test<int>(10);
Test<string>("aa");
//类型推断,省略<>
Test(10);
- 多泛型参数:
<T1,T2>,多个泛型互相独立
cs
//两个不同类型参数
static void Test2<T1, T2>(T1 a, T2 b) { }
//参数+泛型数组
static T1 Test3<T1, T2>(T1 a, T2[] b) { return a; }
三、泛型效率(Stopwatch 测速)
三种传参性能对比:
- 值类型参数:无装箱拆箱,速度最快
- 泛型参数:编译时确定类型,无装箱,速度接近原生值类型
- object 参数 :值类型传入发生装箱、取出拆箱,性能最差
cs
//Stopwatch用来统计代码执行毫秒
Stopwatch sw = new Stopwatch();
sw.Start();
//循环调用
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
四、泛型接口 & 泛型类
1. 泛型接口定义
接口名称后加<T>,接口内部成员使用 T 代表待定类型
cs
interface Ical<T>
{
T Add(T a, T b);
T Sub(T a, T b);
}
2. 两种实现方式
-
实现时直接固定具体类型:类不再是泛型类
public class Calc2 : Ical
{
public int Add(int a, int b) => a + b;
public int Sub(int a, int b) => a - b;
} -
实现时继续沿用泛型 :类也要定义
<T>,创建对象时指定类型public class Calc1
: Ical
{
public T Add(T a, T b) => default(T);
public T Sub(T a, T b) => default(T);
}
//使用
Calc1c = new Calc1 ();
default(T):获取泛型 T 的默认值,值类型默认 0,引用类型默认 null。
五、泛型约束 where
使用where T : 约束缩小泛型可用范围,5 种常用约束:
where T : struct→ T只能是值类型(int/double/struct 等)where T : class→ T只能是引用类型(类、接口、string)where T : new()→ T 必须有无参构造函数where T : 父类名→ T 必须是该类或它的子类where T : 接口名→ T 必须实现该接口
cs
//值类型约束
static void Test2<T>(T a) where T : struct { }
//引用类型约束
static void Test3<T>(T a) where T : class { }
//无参构造约束
static void Test4<T>(T a) where T : new() { }
//父类约束
static void Test5<T>(T a) where T : People { }
//接口约束
static void Test6<T>(T a) where T : IPeople { }
全篇总结
- 多接口:同名不同类型成员需要显式接口实现;接口支持多继承。
- 泛型方法:
<T>定义,调用可类型推断省略尖括号。 - 性能:原生值类型 ≈ 泛型 >> object 装箱。
- 泛型接口:固定类型实现 / 泛型类延续实现两种写法。
- where 约束:struct/class/new ()/ 基类 / 接口五大约束,限制泛型范围。