文章目录
接口
- 接口中只能定义属性,不能定义字段
- 不能包含静态成员
- 接口的成员不能用修饰符,所有成员默认为public,即使是public也不能写
- 类或者结构体实现的时候,类的成员相对于接口成员,只能多,不能少,如果接口中规定的属性拥有get和set,类中必须都有,接口规定只有get,类中可以有get和set
- 当类实现多个接口的时候,使用,分割
- 当类同时继承基类和接口的时候,必须把基类放在前面
代码示例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _02_接口
{
internal class Program
{
static void Main(string[] args)
{
//接口是指一组成员,而不对他们的成员进行实现的引用类型,只能被类和结构体所实现,
类和结构体继承这个接口的时候,必须实现接口中定义的所有的成员
//接口只是一种规范,不具备存储数据和定义方法的能力
//类和结构体实现这个接口的时候,以这个接口的规范为准,进行一一实现,具体怎么实现,
还是由类和结构体决定
//接口:指定规则,应该有什么
//类和结构体:实现接口指定的规则,具体怎么有
}
}
//定义一个接口 接口的名字一般以I开头
//格式:interface 接口的名称{成员}
interface IBook {
//属性
string Name { get; set; }
double Price { get; set; }
void Fn();
void Fn(string v);
}
interface IPaper
{
string Type { get; set; }
string Color { get; set; }
double Height { get;set; }
}
//让某个类实现这个接口,某个类或者结构体实现了这个接口的时候,必须实现这个接口的所有的成员
//一个类可以使用,实现多个接口
class Book : IBook, IPaper
{
public string Name { get; set; }
public double Price { get; set; }
public string Color { get; set; }
public string Type { get; set; }
//实现的类总可以拥有更多的成员,但是不能少
private double price;
public double Height { get; set; }
public void Fn() { }
public void Fn(string v) { }
}
interface IPeople
{
string Name { get; set; }
char Sex { get; set; }
int Age { get; set; }
}
interface IStudent
{
string StudentNo { get; set; }
double Age { get; set; }
}
class People : IPeople
{
public string Name { get; set; }
public char Sex { get; set; }
public int Age { get; set; }
}
class Student : People, IStudent
{
public string StudentNo { get; set; }
//当基类拥有和接口中同名的属性的时候,派生类不需要自己实现,也可以使用new关键字重新实现(了解);
public new double Age { get; set; }
public void Study()
{
Console.WriteLine("我爱学习");
}
}
}
多接口
-
当一个类实现的多个接口中拥有相同的类型和相同的属性,只实现一个即可
-
当一个类实现的多个接口中拥有不同类型的相同属性,需要使用显示接口实现
-
显示接口的实现,不需要也不能加访问修饰符,这个成员访问需要将对象标识为对应的接口的类型
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace _03_多接口
{
internal class Program
{
static void Main(string[] args)
{} } interface IA { string A { get; set; } string B { get; set; } int D { get; set;} void Fn(int v); } interface IB { string B { get; set; } string C { get; set; } string D { get;set; } void Fn(string v); } //类可以实现多个接口 class Tset : IA, IB { public string A { get; set; } //当一个类实现的多个接口中拥有相同的类型和相同的属性,只实现一个即可 public string B { get; set; } //当一个类实现的多个接口中拥有不同类型的相同属性,需要使用显示接口实现 //显示接口的实现,不需要也不能加访问修饰符,这个成员访问需要将对象标识为对应的接口的类型 int IA.D { get; set; } string IB.D { get; set; } public bool D { get; set; } //因为方法可以重载,所以可以直接重载两个接口的方法 public void Fn(int v) { } public void Fn(string v) { } }
}
接口的继承
- 一个接口可以继承另一个接口,如果接口B继承了接口A,某个类实现了接口B的时候,要实现A和B的所有的成员
- 抽象类和接口有什么异同?
-
相同点:
-
1.抽象类和接口都不能实例化 不能new
-
2.都可以包含未实现的方法,由派生类去实现
-
不同点:
-
1.抽象类可以包含非抽象成员 接口只能包含抽象成员(这里的抽象可以理解无实现)
-
2.抽象类只能被实现一个 而接口可以被实现多个(多个接口用逗号隔开·)
-
3.抽象类的派生类需要使用override去覆写抽象类的抽象成员 接口派生类直接覆写
-
4.抽象类可以包含访问修饰符 接口不能有访问修饰符
-
5.抽象类可以包含属性 字段 方法(只能是抽象方法) 接口只能包含属性和方法(不能有抽象方法)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace _04_接口的继承
{
internal class Program
{
static void Main(string[] args)
{} } interface IPeople { string Name { get; set; } int Age { get; set; } } //一个接口可以继承另一个接口,如果接口B继承了接口A,某个类实现了接口B的时候,要实现A和B的所有的成员 interface IStudent : IPeople { string StudentId { get; set;} void Study(); } class Student : IStudent { public string StudentId { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public string Name { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public int Age { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public void Study() { throw new NotImplementedException(); } }
}
索引器
索引器: 一种可以让我们使用 "索引" 来访问对象的一种方式
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _05_索引器
{
internal class Program
{
static void Main(string[] args)
{
//索引器: 一种可以让我们使用 "索引" 来访问对象的一种方式
ClassRoom room = new ClassRoom();
room.Add(new Student() { Name = "吴亦凡", Sex = "男" });
room.Add(new Student() { Name = "罗志祥", Sex = "男" });
room.Add(new Student() { Name = "李云迪", Sex = "女" });
room.Add(new Student() { Name = "郑爽", Sex = "女" });
//需求:想访问数组中的数据一样,通过索引获取班级中学生的姓名
Console.WriteLine(room[0].Name);
Console.WriteLine(room[1].Name);
//通过索引这是值,将会执行索引器中的set代码块
room[3]=new Student() { Name="李易峰",Sex="男"};
Student s = room["吴亦凡"];//返回Name属性为吴亦凡的那个对象
}
}
class Student
{
public string Name { get; set; }
public string Sex { get; set; }
}
class ClassRoom
{
public string No { get; set; }
public string Name { get; set; }
private List<Student> student =new List<Student>();
public void Add(Student s)
{
student.Add(s);
}
//给类中添加一个索引器,这个类的实例就可以想数组一样通过索引进行访问了
//格式:public 返回值类型 this[索引的类型 索引] {}
public Student this[int index]
{
//通过索引来访问数据的时候执行
get
{
//当前访问的索引
Console.WriteLine(index);
return student[index];
}
//通过索引来设置这个数据的时候执行(如果没有set代码块,表示这个索引器是只读)
set
{
student[index] = value;
}
}
public Student this[string index]
{
get
{
//根据传入的值,也就是学生的姓名进行对象的查找
//for (int i = 0; i < student.Count; i++)
//{
// if (student[i].Name==index)
// {
// return student[i];
// }
//}
//return null;
return student.Find(student => student.Name == index);
}
}
}
}
索引器练习
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _06_索引器练习
{
internal class Program
{
static void Main(string[] args)
{
Student student =new Student(new string[] {"吴凡","罗祥","李迪"});
Console.WriteLine(student.Name);
Console.WriteLine(student[0]);
Console.WriteLine(student[1]);
student[3] = "郑";
Console.WriteLine(student[3]);
}
}
class Student
{
// 存储所有学生的名字
string[] names;
//Name 设置默认值 为第一个学生的名字
public string Name { get => names[0]; }
public Student(string[] names) {
this.names = names;
}
public string this[int index] {
//get
//{
// return names[index];
//}
get => names[index];
set
{
if (index>=Name.Length)
{
string[] NewNames=new string[index+1];
Array.Copy(names, NewNames, names.Length);
NewNames[index] = value;
names = NewNames;
}
else
{
names[index]=value;
}
}
}
}
}
命名空间
-
我们的代码越来越多,类越来越多,代码写在同一个文件夹中会导致某个文件结构复杂,代码格式杂乱.命名空间可以让我们在不同的文件中书写代码,不同的文件互相引用
-
namespace 用来定义一个命名空间 命名空间以大驼峰命名法命名
-
如果出现多个命名空间下拥有相同的成员,我们使用的时候会导致不明确的指向
-
可以使用 重命名的方案会进行处理
using myCar1 = Car1.Car;
using myCar2 = Car2.Car;//using 命名空间的名称 引用其他的命名空间
using fanfan;using luozhixiang.xiangxiang;
//如果出现多个命名空间下拥有相同的成员,我们使用的时候会导致不明确的指向
//可以使用 重命名的方案会进行处理
using myCar1 = Car1.Car;
using myCar2 = Car2.Car;//namespace 用来定义一个命名空间 命名空间以大驼峰命名法命名
//格式:namespace 命名空间的名称//我们的代码越来越多,类越来越多,代码写在同一个文件夹中会导致某个文件结构复杂,代码格式杂乱
//命名空间可以让我们在不同的文件中书写代码,不同的文件互相引用
namespace _07_命名空间
{
internal class Program
{
static void Main(string[] args)
{
System.Console.WriteLine("控制台打印");//在同一个项目的不同文件中,可以直接访问相同命名空间下的其他类 People people = new People(); Student student = new Student(); //当某个类和当前类不再同一个命名空间下的时候 //使用 命名空间.目标名称 来引用 fanfan.Book book1 = new fanfan.Book(); //我们如果频繁使用其他命名空间的类,结构体 接口等,需要using关键字引用 //使用using引用之后,就可以把它内部的成员当做相同命名空间下的成员来使用了 fanfan.Book book2 = new fanfan.Book(); Book book3 =new Book(); luozhixiang.xiangxiang.C c = new luozhixiang.xiangxiang.C(); C c2 = new C(); luozhixiang.Tool.Test.AA.A a=new luozhixiang.Tool.Test.AA.A(); Car1.Car cc1 =new Car1.Car(); Car2.Car cc2 = new Car2.Car(); myCar1 my1=new myCar1(); } }
}
引用静态类
静态成员可以在using static 引入之后 直接访问
非静态成员 使用实例进行访问
//using xxx 只能引入命名空间 System.Console 不是命名空间 而是一个类 所以不能被引用
//using System.Console;
//我们可以使用using static 引用类, 就可以直接使用类中的静态成员了
using static System.Console;
using static fanfan.Test;
using fanfan;
namespace _08_引用静态类
{
internal class Program
{
static void Main(string[] args)
{
WriteLine("控制台打印");
WriteLine("控制台打印");
//静态成员可以在using static 引入之后 直接访问
Fn1();
//非静态成员 使用实例进行访问
new Test().Fn2();
}
}
}
引用其他项目
引用同一解决方案下的其他项目
1.当前项目中的"引用"上,右键点击
2.在弹出的菜单中选择添加引用
3.选择 "项目" ==> "解决方案"
4.勾选需要引用的项目
5.点击确定
6.根据对应的项目的命名空间进行引用
引用其他解决方案的项目
1.当前项目中的"引用"上,右键点击
2.在弹出的菜单中选择"添加引用"
3.选择"项目"==>"解决方案"
4.点击"浏览"
5.找到对应解决方案中对应的项目文件 "解决方案目录"--> 项目目录-->bin -->Debug --->Next.x ---> xxx.dll或者 xxx.exe
6.点击确定
7.根据对应项目的命名空间进行引用
上期习题答案
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _01_昨天作业
{
internal class Program
{
static void Main(string[] args)
{
}
}
class Animal
{
//Name、MaxAge(最大寿命)、NowAge(当前的年龄,生成对象时随机设置)、Sex
public string Name { get; set; }
public int MaxAge { get; set; }
private int nowAge;
public int NowAge
{
get => nowAge;
set
{
if (value > MaxAge)
{
throw new Exception("年龄超出最大年龄限制");
}
nowAge = value;
}
}
public char Sex { get; set; }
// 一个随机对象,根据最大年龄设置当前年龄
Random random = new Random();
public Animal(int maxAge)
{
MaxAge = maxAge;
// 在构造方法中进行年龄的初始化
NowAge = random.Next(maxAge + 1);
}
}
class Dog : Animal
{
// 指定一个无参的构造,当没有传递参数时指定MaxAge为34
public Dog() : base(34) { }
// 一个有参的构造,当传递参数时指定MaxAge为传递的值
public Dog(int maxAge) : base(maxAge) { }
public void Speak()
{
Console.WriteLine("汪汪汪");
}
}
class Cat : Animal
{
// 指定一个无参的构造,当没有传递参数时指定MaxAge为39
public Cat() : base(39) { }
// 一个有参的构造,当传递参数时指定MaxAge为传递的值
public Cat(int maxAge) : base(maxAge) { }
public void Speak()
{
Console.WriteLine("喵喵喵");
}
}
class Area
{
/// <summary>
/// 计算矩形的面积
/// </summary>
/// <param name="lenght">长</param>
/// <param name="width">宽</param>
/// <returns>矩形的面积</returns>
public static int GetArea(int lenght, int width)
{
return lenght * width;
}
/// <summary>
/// 计算正方形的编辑
/// </summary>
/// <param name="lenght">边长</param>
/// <returns>正方形的面积</returns>
public static int GetArea(int lenght)
{
return lenght * lenght;
}
/// <summary>
/// 计算梯形的面积
/// </summary>
/// <param name="top">上底长度</param>
/// <param name="botoom">下底的长度</param>
/// <param name="h">高度</param>
/// <returns></returns>
public static int GetArea(int top, int botoom, int h)
{
return (top + botoom) * h / 2;
}
}
//抽象学生类
abstract class Student
{
public abstract int Authority();
}
//本科生
class Undergraduate : Student
{
public override int Authority()
{
return 5;
}
}
//硕士生
class Postgraduate : Student
{
public override int Authority()
{
return 10;
}
}
//博士生
class Doctor : Student
{
public override int Authority()
{
return 15;
}
}
abstract class Pay
{
public string Id { get; set; }//账号
public string Pws { get; set; }//密码
public abstract void payment(double v);//支付的方法,应该接收金额
public abstract void payment(double v, string account);//支付的方法,应该接收金额
}
class WeiXinPay : Pay
{
public override void payment(double v)
{
Console.WriteLine($"使用微信支付{v}圆,账号是{Id},密码{Pws}");
}
public override void payment(double v, string account)
{
Console.WriteLine($"使用微信支付给{account}{v}元,账号是{Id},密码{Pws}");
}
}
class AliPay : Pay
{
public override void payment(double v)
{
Console.WriteLine($"使用支付宝支付{v}圆,账号是{Id},密码{Pws}");
}
public override void payment(double v, string account)
{
Console.WriteLine($"使用支付宝支付给{account}{v}元,账号是{Id},密码{Pws}");
}
}
}
本期习题
-
创建一个用于存储某公司员工信息的类Employee,并且可以通过索引来访问员工的姓名和年龄。(提示:使用字典)
Employee employee = new Employee();
employee[22] = "fanfan"; // 员工年龄22,名字 fanfan employee[22] = "luoluo"; // 员工年龄22,名字 luoluo employee[23] = "Bob"; 员工年龄23,名字 Bob employee["aa"] = 25; employee["Bob"] = 29; //修改Bob的年龄为29
-
创建一个名为DictionaryWrapper的类,它包装了一个Dictionary对象,并提供了一个索引器,允许我们通过键的部分名称来访问字典中的值。(提示,索引器可以接收多个参数)
DictionaryWrapper dictionaryWrapper = new DictionaryWrapper();
// 设置字典中的键值对 dictionaryWrapper["dog"] = "狗"; dictionaryWrapper["cat"] = "猫"; dictionaryWrapper["elephant"] = "大象"; dictionaryWrapper["dolphin"] = "海豚"; // 输出字典中的值 Console.WriteLine("通过完整键访问:"); Console.WriteLine("dog的值是:" + dictionaryWrapper["dog"]); // 狗 Console.WriteLine("cat的值是:" + dictionaryWrapper["cat"]); // 猫 Console.WriteLine("elephant的值是:" + dictionaryWrapper["elephant"]); // 大象 Console.WriteLine("dolphin的值是:" + dictionaryWrapper["dolphin"]); // 海豚 Console.WriteLine("\n通过键的部分名称访问:"); Console.WriteLine("以\"do\"开头的键的第一个值是:" + dictionaryWrapper["do", 0]); // 狗 Console.WriteLine("以\"do\"开头的键的第二个值是:" + dictionaryWrapper["do", 1]); // 海豚
-
将练习1中的类在其他的项目中使用
-
将练习2中的类提取到另一个解决方案,并在当前项目中使用