文章目录
前言
C#是面向对象的编程语言,面向对象编程的四项基本原则:
-
抽象:将实体的相关特性和交互建模为类,以定义系统的抽象表示
-
封装:隐藏对象的内部状态和功能,并仅允许通过一组公共函数进行访问
-
继承:根据现有抽象创建新抽象的能力
-
多形性(多态):跨多个抽象以不同方式实现继承属性或方法的能力
类的继承
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)
{
//继承:根据现有的类,生成一个新的类
//当创建一个类的时候,可以不需要重新编写新的成员和方法,而是继承自现有的类,
这个被继承类我们称之为"父类"(基类),这个新的类我们称之为"子类"(派生类)
//如果一个类没有继承自任何类,那么默认他继承object,C#中所有类,
都直接或者间接继承自 object,object是所有类的"终极基类"
Student student = new Student()
{
Name = "Test",
Age = 18,
StudentId = "20240321",
Schoole = "爱疯学校"
};
student.Eat();
student.Study();
SamllStudetn samllStudetn = new SamllStudetn() { Name = "小学生", StudentId = "1232132" };
samllStudetn.Cry();
//任意类型的数据,都可以赋值给object类型的变量
object aa = 10;
//一个类的实例化对象,可以被赋值给他的父类型
object s1 = new SamllStudetn();
Student s2 = new SamllStudetn();
People s3 = new SamllStudetn();
}
}
//基类
class People
{
public string Name { get; set; }
public int Age { get; set; }
public char Sex { get; set; }
public void Eat()
{
Console.WriteLine("吃饭");
}
}
//派生类
//在定义一个类的时候 使用 ":" 基类 实现继承
//当一个类继承自另一个类的时候,子类将自动拥有父类的成员(成员变量和成员方法)
class Student : People
{
public string StudentId { get; set; }
public string Schoole { get; set; }
public void Study()
{
Console.WriteLine($"我是{Name},在{Schoole}学习");
}
}
//基类和派生类并不是绝对的一个概念,是相对的,一个类可以同时是基类和派生类
class SamllStudetn : Student
{
public void Cry()
{
Console.WriteLine("背着炸药包,我要炸学校");
}
}
}
继承类的构造函数
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)
{
Man man = new Man();
Console.WriteLine(man.IQ);
Console.WriteLine(man.Sex);
Console.WriteLine(man.Name);
}
}
class People
{
public string Name { get; set; }
public char Sex { get; set; }
public readonly int IQ;
private Random r = new Random();
public People(){
Console.WriteLine("1.People的构造函数");
IQ=r.Next(0,250);
Name = "吴凡";
}
}
class Man : People
{
//当new一个类的时候,这个子类创建之前父类就应该先存在,因此会先执行
父类的构造函数进行父类的创建,然后在执行子类的构造函数
public Man()
{
Console.WriteLine("2.Man的构造函数");
Sex = '男';
}
//子类中直接操作定义在父类的属性和字段
public void Fn()
{
Name = "罗祥";
}
}
}
子类访问父类
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)
{
//
//new People();
//new People("吴凡",'男');
Man man1 = new Man();
Console.WriteLine(man1.Name);
Console.WriteLine(man1.Sex);
Man man2 = new Man("刘凡");
Console.WriteLine(man2.Name);
Console.WriteLine(man2.Sex);
}
}
class People
{
public string Name { get; set; }
public char Sex { get; set; }
//类里面可以拥有多个同名的但是不同参数的方法,当调用方法的时候,
会自动根据方法传递的参数,选择不同的方法执行(方法(函数)重载)
public People()
{
Console.WriteLine("People的无参构造函数");
}
public People(string name,char sex)
{
Console.WriteLine("People的有参构造函数");
Name = name;
Sex = sex;
}
}
class Man : People
{
//子类被创建的时候,默认会执行父类的无参构造方法,不会执行有参构造方法
//public Man():base() 自动生成这样的代码,等价于直接执行父类的无参构造方法
public Man()
{
Console.WriteLine("Man的无参构造函数");
}
//子类中使用base 表示父类
//this表示当前类
//在子类的构造方法后面添加 :base 可以直接执行父类的构造方法
public Man(string name):base(name,'男')
{
Console.WriteLine("Man的有参构造函数");
}
}
}
访问修饰符测试
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)
{
Man man =new Man();
Console.WriteLine(man.a);
// Console.WriteLine(man.b);
Console.WriteLine(man.c);
//Console.WriteLine(man.d);
Console.WriteLine(man.e);
}
}
//public:公共的,当前类,子类,实例都可以访问到
//private:私有的,仅能在当前类内部访问,子类,实例都不能访问
//internal:只能在当前项目访问
//protected:只有该类以及子类可以访问.实例不能访问
//protected internal:能在当前类,子类,实例中访问,在别的项目(引用了这个项目)中,
可以在子类中访问,实例不能访问
public class People
{
public int a = 2;
private int b=3;
internal int c = 4;
protected int d = 5;
protected internal int e = 6;
public void PeopleFn()
{
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
Console.WriteLine(d);
Console.WriteLine(e);
}
}
class Man : People
{
public void ManFn()
{
Console.WriteLine(a);
//Console.WriteLine(b);
Console.WriteLine(c);
Console.WriteLine(d);
Console.WriteLine(e);
}
}
}
//----------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using _04_访问修饰符;
namespace _04_测试
{
internal class Program
{
static void Main(string[] args)
{
Test test= new Test();
Console.WriteLine(test.a);
// Console.WriteLine(test.c);
// Console.WriteLine(test.e);
}
}
class Test : People
{
public void TestFn()
{
Console.WriteLine(a);
Console.WriteLine(d);
Console.WriteLine(e);
}
}
}
访问修饰符/范围 | 当前类 | 子类 | 实例对象 | 引用当前项目的项目子类 | 引用当前项目实例对象 |
---|---|---|---|---|---|
public | √ | √ | √ | √ | √ |
private | √ | × | × | × | × |
internal | √ | √ | √ | × | × |
protected | √ | √ | × | √ | × |
protected internal | √ | √ | √ | √ | × |
多态_函数重载
方法的重载注意事项:
1.同一个方法的不同重载可以是参数数量不同
2.也可以是参数的类型不同
3.和返回值类型无关,(不同的返回值类型不算重载)
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)
{
//多态指同一个行为具有不同的表现形式的能力
//多态性可以是静态或者动态的,静态指的是在编译过程中发生的,动态指的
是在运行过程中发生的
//静态多态:
//在编译过程中,通过方法重载和运算符重载来实现编译时多态,也称为静态绑定
或早期绑定
//动态多态:
//在运行过程中:通过抽象方法,重写方法,隐藏方法实现运行时多态,也称之为动
态绑定或后期绑定
//我们对类进行相同的new行为,出现了不同的效果,这个就可以理解为多态
new People();
new People("吴亦凡");
People p1 = new People();
p1.Eat();
p1.Eat("大盘鸡");
Console.WriteLine();
}
}
//
class People
{
public string Name { get; set; }
//函数的重载
//可以在同一个范围内,对相同的函数名有多个定义
//函数的定义必须彼此不同,可以是参数列表中的参数类型不同,也可以是参数的个数不同
//不能重载只有返回值类型不同的函数声明
public People()
{
Console.WriteLine("无参构造函数");
}
public People(string name)
{
Console.WriteLine("string类型有参构造函数");
}
public People(int age)
{
Console.WriteLine("int类型的有参构造函数");
}
public People(int age,string name)
{
Console.WriteLine("int和string类型的有参构造函数");
}
public People( string name, int age)
{
Console.WriteLine("string和int类型的有参构造函数");
}
public void Eat()
{
Console.WriteLine("我在吃饭");
}
public void Eat(string food)
{
Console.WriteLine("我在吃"+ food);
}
public void Eat(int count)
{
Console.WriteLine($"我今天吃了{count}饭");
}
public void Eat(int count,string food)
{
Console.WriteLine($"我今天吃了{count},全是{food}");
}
}
}
多态_运算符重载
可重载与不可重载的运算符
运算符 | 可重载性 |
---|---|
+、-、!、~、++、– | 这些一元运算符可以进行重载 |
+、-、*、/、%、&、|、^、<<、>>、=、!=、<、>、<=、>= | 这些二元运算符可以进行重载,需要注意的是某些运算符必须成对重载 |
&&、|| | 无法重载逻辑运算符 |
(type)var_name | 强制类型转换运算符不能重载 |
+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>= | 复合赋值运算符不能显式重载。 但在重载二元运算符时,也会隐式重载相应的复合赋值运算符,例如重载了+ 运算符也会隐式的重载+= |
^、=、.、?.、? : 、??、??=、…、->、=>、as、await、checked、unchecked、default、delegate、is、nameof、new、sizeof、stackalloc、switch、typeof | 这些运算符无法进行重载 |
注意:比较运算符必须成对重载,也就是说,如果重载一对运算符中的任意一个,则另一个运算符也必须重载。比如==
和!=
运算符、<
和>
运算符、<=
和>=
运算符。
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)
{
Box b1=new Box() { Width=10,Height=10,Length=10};
Box b2 = new Box() { Width = 20, Height = 20, Length = 20 };
//计算这两个盒子的体积的和
Console.WriteLine(b1 + b2);
//计算两个盒子相减,生成一个新的Box
Box b3 = b2 - b1;
Console.WriteLine(b3.Height);
//比较两个盒子的大小
Console.WriteLine(b1>b2);
Box b4 = b1++;
}
}
class Box
{
public double Length { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public double Volume
{
get
{
return Length * Width * Height;
}
}
//我们可以重新定义某个类的运算符,我们自定义的运算符,可以对我们的对象进行运算操作
//重载+运算符 计算两个盒子的体积
//一个运算符的重载,其实就是一个方法,当对该类的对象进行对应的运算符操作的时候,
会自动执行这个重载的运算符方法
//格式:public static 返回值类型 operator 要重载的运算符(参数列表){}
//+ 运算符重载接收两个参数 表示进行运算的两个对象
public static double operator +(Box box1,Box box2)
{
return box1.Volume + box2.Volume;
}
public static Box operator -(Box box1, Box box2)
{
return new Box
{
Width = box1.Width - box2.Width,
Height = box1.Height - box2.Height,
Length = box1.Length - box2.Length
};
}
public static bool operator >(Box box1, Box box2)
{
return box1.Volume >box2.Volume;
}
public static bool operator <(Box box1, Box box2)
{
return box1.Volume < box2.Volume;
}
public static bool operator ==(Box box1, Box box2)
{
return box1.Volume == box2.Volume;
}
public static bool operator !=(Box box1, Box box2)
{
return box1.Volume != box2.Volume;
}
public static Box operator ++(Box box)
{
box.Width++;
box.Height++;
box.Length++;
return box;
}
public static Box operator --(Box box)
{
box.Width--;
box.Height--;
box.Length--;
return box;
}
}
}
抽象类
C#中可以创建抽象类,用于提供类的部分成员实现,当某一个类继承自这个抽象类的时候,需要手动实现这个类中的抽象成员
抽象类中可以包含抽象方法,这个抽象方法不能去实现,而是在某个类继承自这个抽象类的时候实现
总结: 抽象类和普通类的区别?
- 抽象类不能实例化,普通类可以实例化
- 抽象类中不一定要有抽象方法,普通类中不能有抽象方法
- 抽象类可以和普通类一样,有普通方法
- 抽象类可以继承自抽象类,子类如果不是抽象类,则必须重写抽象类中的全部抽象方法
- 抽象方法就是被子类重写的,所以不能使用private修饰符
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _07_抽象类
{
internal class Program
{
static void Main(string[] args)
{
//抽象类:就是指设计为被继承的类,抽象类只能被用作其他的类的基类
//new Print();
ColorPrint p1= new ColorPrint();
p1.Print("6666");
}
}
// 使用 abstract class 创建一个抽象类 写法和class相同
abstract class Printer
{
public string Name { get; set; }
public int Price { get; set; }
//抽象类中可以定义抽象方法
//给某个方法添加一个abstract关键字,把这个方法修饰成抽象方法,抽象方法不需要也不能拥有内容
public abstract void Print(string value);
}
//当某个非抽象类继承自一个抽象类之后,必须实现这个类中的抽象方法
class ColorPrint:Printer
{
//override 重写和实现抽象类中的抽象方法
public override void Print(string value)
{
Console.WriteLine("打印彩色的内容"+value);
}
}
class BawPrint : Printer
{
public override void Print(string value)
{
Console.WriteLine("打印黑白内容"+value);
}
}
}
虚方法
总结:抽象方法和虚方法的区别?
- 抽象方法只能定义在抽象类中,虚方法可以定义在普通类中
- 抽象方法不可以有内容,必须在派生类中实现,虚方法可以有内容,可以不再派生类中实现,不实现则使用基类的方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _08_虚方法
{
internal class Program
{
static void Main(string[] args)
{
//类的动态多态,是由抽象方法和虚方法实现的
//虚方法可以定义在一个普通的类中,可以理解为一个类中的抽象方法,只是这个方法可以在类中实现,也可以在派生类中实现
Chinese chinese = new Chinese();
chinese.Speak();
Man man =new Man();
man.Speak();
}
}
class People
{
public string Name { get; set; }
//给某个方法添加一个 virtual 关键字,把这个方法修饰成虚方法,虚方法可以有实现(内容)
public virtual void Speak()
{
Console.WriteLine("打招呼");
}
}
class Chinese : People
{
//override 重写和覆盖父类的虚方法
public override void Speak()
{
Console.WriteLine("吃了没?");
}
}
class Man : People
{
}
}
new 和override
相同: new和override 都可以对基类的成员"覆盖"
不同
- new 隐藏基类的成员(覆盖基类所有的成员的虚方法,非虚方法)
- override是 覆盖基类成员(只能重写基类的抽象方法和虚方法)
- new 是隐藏, 基类和派生类各持一份,互不干扰 对象是什么类型 使用对应的类的方法
- override 是覆盖 将会重写基类的虚方法和抽象方法,只此一份,不管是什么类型,都只有一个
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _09_new_和override
{
internal class Program
{
static void Main(string[] args)
{
Man m1=new Man();
People m2=new Man();
m1.Test1();//Man-Test1
m2.Test1();//People_Test1
m1.Test2();//Man-Test2
m2.Test2();//Man-Test2
Woman w1=new Woman();
People w2 = new Woman();
w1.Test1();
w2.Test1();
w1.Test2();
w2.Test2();
}
}
class People
{
public void Test1()
{
Console.WriteLine("People_Test1");
}
public virtual void Test2()
{
Console.WriteLine("People_Test2");
}
public virtual void Test3()
{
Console.WriteLine("People_Test3");
}
}
class Man : People
{
//当类中的成员是虚方法的时候,可以使用override进行处理
public new void Test1()
{
Console.WriteLine("Man-Test1");
}
//当派生类和基类中拥有同名的成员的时候,编译器会发出一个警告"隐藏继承的成员xxxx.如果是有意隐藏,请使用new关键字"
public override void Test2()
{
Console.WriteLine("Man-Test2");
}
}
class Woman : People
{
public new void Test1()
{
Console.WriteLine("Woman-Test1");
}
public override void Test2()
{
Console.WriteLine("Woman-Test2");
}
public override void Test3()
{
Console.WriteLine("Woman-Test3");
}
}
}
密封类和静态类
- 给某个类添加一个 sealed 关键字,把这个类修饰成密封类,密封类不能被其他的类继承
- 给某个类添加一个 static 关键字,把这个类修饰成静态类,静态类不能实例化(不能new)也不能被继承,并且静态类中只能拥有静态成员
注意:抽象类的作用就是让别人继承的,抽象类不能被定义为密封类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _10_密封类和静态类
{
internal class Program
{
static void Main(string[] args)
{
new Test();
// new Test3();
}
}
sealed class Test
{
}
// class Test2:Test {
// }
static class Test3
{
public static int a = 1;
}
}
结构体
类和结构的区别:
1.结构体是值类型,类是引用类型
2.结构体不能继承其他的类和结构体,也不能被类和其他的结构体所继承
3.不能定义无参数的构造方法,可以定义有参的构造方法
4.不能对结构体的字段和属性进行初始化
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _11_结构体
{
internal class Program
{
static void Main(string[] args)
{
Book book = new Book();
book.Name = "坏蛋是怎么样炼成的";
book.Price = 100;
book.ShowInfo();
Book book2 = new Book();
book.Price = 22;
book2.ShowInfo();
}
}
//结构体是值类型的数据,它可以让单一的变量可以存储多个数据.和类及其相似,也可以存储字段,属性,方法,可以理解为结构体就是值类型的对象
//格式: struct 结构体的名字 {内容}
struct MyStruct
{
//和类相似,在结构体中可以定义类似于成员的结构成员
//字段
private int a;
//属性
public string A { get; set; }
public void Test()
{
}
}
struct Book
{
public string Name { get; set; }
public double Price { get; set; }
public void ShowInfo()
{
Console.WriteLine($"{Name}的售价为{Price}");
}
//结构体不能定义无参的构造方法
//public Book() {
//}
public Book(string name, double price)
{
this.Name = name;
this.Price = price;
}
}
//struct Book1 : Book
//{
//}
//类和结构的区别:
//1.结构体是值类型,类是引用类型
//2.结构体不能继承其他的类和结构体,也不能被类和其他的结构体所继承
//3.不能定义无参数的构造方法,可以定义有参的构造方法
//4.不能对结构体的字段和属性进行初始化
}
上期习题答案
-
验证一个车牌号码是否符合中国大陆的规范:
// 例如豫A12345、粤BD12345Z等 Regex regexPlateNumber = new Regex(@"^[\u4e00-\u9fa5][A-Z](([A-Z0-9]{6})|([DF][A-HJ-NP-Z0-9]{5}))$");
-
正则验证邮箱格式是否正确:
// 基本电子邮件地址匹配,注意这不包括所有有效邮件地址的可能性,只是最常见的形式 Regex regexEmail = new Regex(@"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$");
-
判断
xxxx-xx-xx
格式的字符是否为有效日期(假设月份和日期总是有效):// 简化版,不验证实际每个月的具体天数或闰年逻辑,只会检测基础格式。 Regex regexSimpleDate = new Regex(@"^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$");
现在让我们将这些正则表达式应用到 C# 代码中以进行实际验证:
using System;
using System.Text.RegularExpressions;
class Program {
static void Main() {
Console.WriteLine("请输入一个车牌号码:");
string plateNumberInput = Console.ReadLine();
var regexPlateNumber = new Regex(@"^[\u4e00-\u9fa5][A-Z](([A-Z0-9]{6})|([DF][A-HJ-NP-Z0-9]{5}))$");
bool isPlateNumberValid = regexPlateNumber.IsMatch(plateNumberInput);
Console.WriteLine(isPlateNumberValid ? "车牌有效。" : "车牌无效。");
Console.WriteLine("\n请输入一个邮箱地址:");
string emailInput = Console.ReadLine();
var regexEmail = new Regex(@"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$");
bool isEmailValid = regexEmail.IsMatch(emailInput);
Console.WriteLine(isEmailValid ? "邮箱地址有效。" : "邮箱地址无效。");
Console.WriteLine("\n请输入一个日期(格式为 xxxx-xx-xx):");
string dateInput = Console.ReadLine();
var regexSimpleDate = new Regex(@"^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$");
bool isDateValid = regexSimpleDate.IsMatch(dateInput);
Console.WriteLine(isDateValid ? "日期有效。" : "日期无效。");
}
}
运行程序后,在控制台中输入相应信息将对上述各项内容进行校验。
请注意,通用电子邮件验证是一个复杂任务且存在边缘情况;要创建一个能够涵盖所有合法电子邮件地址的正则表达式非常困难并且不太实际。上面给出的电子邮件正则表达式遵循基本标准但未涉及到所有复杂场景。
同理,对于日期也是如此——简单地验证日期字符串格式而不考虑月份和年份特有的日期规则会导致非法日期(如 11 月 31 日)被判断为有效。如果您需要更准确地验证,请考虑使用内置于 .NET 的 DateTime 类型解析功能:
DateTime temp;
bool isValidDate = DateTime.TryParseExact(dateInput, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out temp);
这种方式调用 DateTime.TryParseExact
方法可以比任何正则表达式都更准确地检验日期字符串是否表示有效日期。
本期习题
-
定义一个Animal类,拥有Name、MaxAge(最大寿命)、NowAge(当前的年龄,生成对象时随机设置)、Sex,
一个Dog类,继承自Animal类,拥有Speak方法,发出汪汪汪的声音
一个Cat类,继承自Animal类,拥有Speak方法,发出喵喵喵的声音
-
定义一个类,实现计算面积 可以计算矩形,正方形,梯形的面积(多态)
-
定义一个类实现图书馆管理学生借书权限(抽象)
对于本科生来说,只能借5本书,硕士生可以借10本,而博士生则可以借15本书
-
定义一个抽象类,拥有属性账号、密码、(抽象)支付方法
标签:Console,C#,多态,System,WriteLine,new,using,抽象类,public From: https://blog.csdn.net/2401_82410658/article/details/136915256觉得文章还不错,可以关注,点赞,收藏。主页有C#教程专栏,欢迎订阅!!!