c#软件开发学习笔记--索引器、接口、泛型
·
c#软件开发学习笔记
一、索引器
索引器允许一个对象可以像数组一样使用下标的方式来访问。
添加一个this[int index] 这种属性
//调用
//定义学生对象
Student stu = new Student(new string[] { "六一","高考","中考","端午"});
Console.WriteLine(stu.Name);//默认值为stu对象的第一个
stu[0] = "期末";
Console.WriteLine(stu[0]);
Console.WriteLine(stu[1]);
Console.WriteLine(stu[2]);
Console.WriteLine(stu[3]);
stu[4] = "12"; //set访问器
Console.WriteLine(stu[4]);//走get方法
//***************************************//
//定义学生类 定义姓名属性 定义构造函数传递一个数组参数
public class Student
{
private string[] names = new string[4];//定义字符串数组长度为4
public string Name { get => names[0]; } //names第一个
public Student(string[] s)
{
names = s;
}
public string this[int index] //使用stu[0]方式访问this[int index]属性
{
get
{
return names[index];
}
set
{
if (index>=names.Length) //证明names数组长度不过 需要长度加1
{
//新数组的长度为原先数组的长度+1
string[] newArr = new string[names.Length+1];
//把原数组的元素拷贝到新数组里面
Array.Copy(names, newArr,names.Length);
names = newArr;
}
// 直接把value值赋值指定位置元素 新数组的新位置添加一个元素
names[index] = value;
}
}
}
二、接口
接口(interface):主要是定义能力契约,接口里面的成员都是未实现的,类或结构体实现这个接口的时候,必须实现接口中定义的所有的成员
1.代码示例
//接口的名称一般以I开头
//书的接口
interface IBook
{
int Id { get; set; }
int Name { get; set; }
void F1();
}
//纸张的接口
interface IPaper
{
string color { get; set; }
void F2();
}
//类可以实现多个接口
class Book : IBook, IPaper
{
public int Id { get ; set ; }
public int Name { get ; set ; }
public string color { get ; set ; }
public void F1()
{
}
public void F2()
{
}
}
2.接口与抽象类
接口和抽象类的区别
-
相同点:
1.抽象类和接口都不能实例化
2.都可以包含未实现的方法,由派生类去实现 -
不同点:
1.抽象类可以包含非抽象方法,接口不能包含抽象成员
2.抽象类只能被继承一个 接口可以被实现多个
3.抽象类的派生需要使用override覆写类的成员 接口派生直接覆写
4.抽象类可以包含访问修饰符 接口不能有访问修饰符
5.抽象类可以包含 属性 字段 方法 接口可以包含属性和方法
| 对比维度 | 接口 (Interface) | 抽象类 (Abstract Class) |
|---|---|---|
| 定义方式 | 使用 interface 关键字 |
使用 abstract class 关键字 |
| 继承特性 | 使用 : 实现(implements) |
使用 : 继承(extends) |
| 成员实现要求 | 所有成员默认为抽象,必须在实现类中实现 | 可以包含抽象成员(需实现)和具体成员(可继承) |
| 构造函数支持 | 不支持构造函数 | 支持构造函数,可用于初始化基类状态 |
| 成员支持 | 不支持实例字段,仅支持属性、方法 | 支持字段、属性、方法 |
| 访问修饰符限制 | 成员默认 public,不能使用其他修饰符 |
成员可使用 public、protected、private、internal |
| 多继承能力 | 支持多接口实现 | 不支持多类继承,仅支持单继承 |
| 静态成员 | 不支持静态成员 | 支持静态成员(字段、方法、属性) |
| 设计目的 | 定义行为契约,强调"能做什么" | 提供基类实现,强调"是什么" |
| 使用场景 | 定义跨类层次的行为规范、实现多态、解耦模块 | 定义类层次结构的公共基类、共享代码实现 |
总结:接口定能力,抽象定归属;多继承用接口,共代码用抽象。|
三、泛型
泛型(Generic):广泛的类型,当我们定义一个方法时候不想对返回值或参数指定具体的类型,就可以把类型定义成泛型,当我们调用这个方法时传递进去类型
1. 运行原理
控制台程序最终会编译成一个exe程序,exe被点击的时候,会经过JIT(即时编译器)的编译,最终生成二进制代码,才能被计算机执行。泛型加入到语法以后,VS自带的编译器又做了升级,升级之后编译时遇到泛型,会做特殊的处理:生成占位符。再次经过JIT编译的时候,会把上面编译生成的占位符替换成具体的数据类型。
泛型的运行分为两个阶段:
- 编译阶段:VS编译器遇到泛型时生成占位符
- JIT编译阶段:即时编译器(Just In Time)将占位符替换为具体数据类型
2.泛型方法
class Program
{
static void Main(string[] args)
{
// 调用时指定类型
Console.WriteLine(Test<int>(10));
Console.WriteLine(Test<string>("aa"));
Console.WriteLine(Test<bool>(true));
// 类型推断,可省略<>
Console.WriteLine(Test(10));
Console.WriteLine(Test("aa"));
}
// 泛型方法:返回类型和参数类型由调用时指定
static T Test<T>(T a)
{
return a;
}
// 多泛型参数
static void Test2<T1, T2>(T1 a, T2 b) { }
// 泛型数组参数
static T1 Test3<T1, T2>(T1 a, T2[] b)
{
return a;
}
}
3.泛型类
泛型类在实例化的时候指定类型,类中所有泛型位置使用相同的类型。
public class Calc<T> : Ical<T>
{
public T Add(T a, T b)
{
return default(T); // 返回对应类型的默认值
}
public T Sub(T a, T b)
{
return default(T);
}
}
// 使用
Calc<int> c1 = new Calc<int>();
Calc<string> c2 = new Calc<string>();
4.泛型接口
泛型接口在接口名后面添加 <T>,在接口实现的时候确定泛型接口的类型。
internal interface Ical<T>
{
T Add(T a, T b);
T Sub(T a, T b);
}
// 实现时指定具体类型
public class Calc2 : Ical<int>
{
public int Add(int a, int b) { return a + b; }
public int Sub(int a, int b) { return a - b; }
}
// 使用类的泛型决定接口的泛型类型
public class Calc1<T> : Ical<T>
{
public T Add(T a, T b) { return default(T); }
public T Sub(T a, T b) { return default(T); }
}
5.泛型约束
泛型约束通过 where 关键字添加,可以把泛型的范围缩小,使其不那么广泛。
| 约束语法 | 说明 |
|---|---|
where T : struct |
T只能是值类型 |
where T : class |
T只能是引用类型 |
where T : new() |
T必须有无参构造函数 |
where T : 类名 |
T必须是该类或其派生类 |
where T : 接口名 |
T必须实现该接口 |
class People
{
public People() { }
public People(string b) { }
}
class Stu : People { }
interface IPeople { }
class SS : IPeople { }
class Program
{
// 无约束
static void Test1<T>(T a) { }
// 值类型约束
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 { }
}
//使用示例
Test2(10); // 正确:值类型
Test3("ss"); // 正确:引用类型
Test4(new People()); // 正确:有无参构造函数
Test5(new People()); // 正确:People类型
Test5(new Stu()); // 正确:People的派生类
Test6(new SS()); // 正确:实现IPeople接口
更多推荐
所有评论(0)