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不能使用其他修饰符 成员可使用 publicprotectedprivateinternal
多继承能力 支持多接口实现 不支持多类继承,仅支持单继承
静态成员 不支持静态成员 支持静态成员(字段、方法、属性)
设计目的 定义行为契约,强调"能做什么" 提供基类实现,强调"是什么"
使用场景 定义跨类层次的行为规范、实现多态、解耦模块 定义类层次结构的公共基类、共享代码实现

总结:接口定能力,抽象定归属;多继承用接口,共代码用抽象。|

三、泛型

泛型(Generic):广泛的类型,当我们定义一个方法时候不想对返回值或参数指定具体的类型,就可以把类型定义成泛型,当我们调用这个方法时传递进去类型

1. 运行原理

控制台程序最终会编译成一个exe程序,exe被点击的时候,会经过JIT(即时编译器)的编译,最终生成二进制代码,才能被计算机执行。泛型加入到语法以后,VS自带的编译器又做了升级,升级之后编译时遇到泛型,会做特殊的处理:生成占位符。再次经过JIT编译的时候,会把上面编译生成的占位符替换成具体的数据类型。

泛型的运行分为两个阶段:

  1. 编译阶段:VS编译器遇到泛型时生成占位符
  2. 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接口

更多推荐