类
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)
{
//类:就是一个定义了数据类型的蓝图(模板),如:人类,动物类,汽车类....一个类的创建
实际上并没有任何的数据,它仅仅定义了一个类是什么,意味着什么,由什么东西组成,
可以执行什么操作...
//对象:对象就是类的实例,由某一个类实打实创建(new)出来的,一个实际拥有的产物,
如:一个人 一只狗 一只鸟 ....
//类成员:一个类中包含的重要信息(属性)和行为(方法),这些信息我们统称为类成员
//如: 人类应该拥有名字 性别 年龄 身高... 应该拥有 吃 和 拉 撒 睡....
//类和对象是 面向对象编程语言的一大核心
//类:就是拥有相同信息和行为的抽象的一个概念,某一类事物的总称
//对象:是实实在在的个体,由类进行创建,是类的实例化
//需求:计算矩形的面积
//面向过程
//Rectangle rect1=new Rectangle();
//Console.WriteLine("请输入矩形的宽度");
//rect1.Width =int.Parse(Console.ReadLine());
//Console.WriteLine("请输入矩形的长度");
//rect1.Height =int.Parse(Console.ReadLine());
//Console.WriteLine($"矩形的面积为{rect1.Area()}");
}
}
//类的创建
//类一般创建在namespace代码块中,以class关键字开头, 类的主体由一个{}包裹
/*
* 格式:
*
* 访问修饰符 class 类名{
*
* 类成员,分为三大类:字段 属性 和方法
*
* 成员变量,也叫做字段
* 访问修饰符 成员的类型 成员的名称1
* 访问修饰符 成员的类型 成员的名称2
* 访问修饰符 成员的类型 成员的名称3
*
* 成员方法:
*
* 访问修饰符 方法的返回值类型 方法名称1(){
* 方法的实现
* }
*
* 访问修饰符 方法的返回值类型 方法名称2(){
* 方法的实现
* }
*
*
* }
*
* 访问修饰符:指定了一个类以及这个类的成员的可访问性,通过这个标识控制这个类
* 以及整个类的某个成员的可访问性
*
* public:公共的,所有地方可以访问(重要)
* private:私有的,类内部可以访问(重要)
* internal:只能在当前项目访问(重要)
* protected:只有该类以及子类可以访问(后续讲解)
* protected internal:允许在同一程序集中的任何位置以及从包含类派生的类型内部访问成 员。这是一种介于 protected(受保护)和 internal(内部)之间的权限。(后续讲解)
*
*
* 类和类成员都有默认的修饰符
*
* 类的默认的修饰符 internal 只能在当前项目访问
* 类成员默认的修饰符:private:私有的,类内部可以访问
*
*/
class People
{
//成员变量
string name;
int age;
char sex;
//成员方法
void eat()
{
Console.WriteLine("吃饭");
}
void sleep()
{
Console.WriteLine("睡觉");
}
}
//class Rectangle
//{
// //属性
// public int Width { get; set; }
// public int Height { get; set; }
// //行为
// public int Area()
// {
// return Width*Height;
// }
//}
}
对象
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)
{
//对象是类的实现,使用new操作符根据一个类创建该类的实例化对象
//当我们创建一个类的同时,也会拥有一个数据类型,所以这个类实例化出来的对象,都属于这个类型
People p1 = new People();
People p2 = new People();
//通过 对象名.成员名称 的方式来操作对象的成员
//设置: 对象名.成员名称=值
p1.name = "吴凡";
p1.age = 18;
p1.sex = '男';
p2.name = "郑爽";
p2.age = 19;
p2.sex = '女';
//获取: 对象名.成员名称
Console.WriteLine($"p1的名字是{p1.name}");
Console.WriteLine($"p2的名字是{p2.name}");
//使用 对象名.成员方法() 的方式调用对象的方法
p1.eat();
p2.eat();
//对象也可以在初始化的同时进行对象成员的初始化
People p3 = new People() { name = "罗志祥", age = 23,sex='男' };
}
}
class People
{
//默认类成员的访问修饰符是 private 私有的 类内部可以访问
//成员变量
public string name;
public int age;
public char sex;
double money;
//成员方法
public void eat()
{
this.money = 100;
Console.WriteLine("吃饭");
//在类的方法中,使用this来表示当前类创建的那个对象
Console.WriteLine($"{this.name}吃饭");
//访问当前类的其他的成员可以省略this
Console.WriteLine($"{name}吃饭");
Console.WriteLine(money);
}
public void sleep()
{
Console.WriteLine("睡觉");
}
}
}
修饰符使用范围测试
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using _03_测试;
namespace _03_修饰符使用范围
{
internal class Program
{
static void Main(string[] args)
{
//引用其他的项目中的类
//1.在当前项目"引用" 上右键
//2."添加引用"==>"项目"==>勾选需要使用的类所在的项目
//3.点击"确定"
//4.在当前项目中 使用 using 引入类项目所在的命名空间(namespace 后面的名字)
Cat cat = new Cat();
}
}
}
//---------------------------------
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)
{
Cat cat = new Cat();
}
}
//类的默认的修饰符是internal:只能在当前项目访问
public class Cat
{
public string name;
}
}
属性和字段
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)
{
People people = new People();
people.name = string.Empty;
people.Age = 160;
Console.WriteLine(people.Age);
//总结:字段和属性的区别
//1.字段和属性都是成员变量
//2.字段一般是私有的,属性一般是公开了
//3.字段以小驼峰命名,属性以大驼峰命名
//4.字段可以存储数据,属性不能存储数据
Dog dog = new Dog();
dog.Age = 10;
dog.Color = Dog.Ecolor.黄;
}
}
class People
{
//类拥有成员变量和成员方法
//成员变量就是字段,用于存储对象的信息
public string name;
//类的成员可以通过访问修饰符限制可访问性,如果一个成员的修饰符为public,
这个成员变量有可能会被随意的更改,出现一些意料之外的值,
//比如:name出现无字,age出现负数,sex出现男和女之外....
//为了保证对象的数据不被随意的更改,我们通常会把属性定义为公开的
成员变量(使用大驼峰),把字段定义私有的成员变量(使用小驼峰)
private int age;
public int Age
{
//获取Age属性的时候执行
get
{
Console.WriteLine("get方法执行了");
//get代码块中通过return返回当前属性的值
return age;
}
//设置Age属性的时候执行
set
{
Console.WriteLine("set方法执行了");
//set 方法中有一个value.这个value就是修改之后的值
Console.WriteLine(value);
if (value < 0)
{
//抛出一个错误,让代码报错并停止
throw new Exception("Age属性的值不能小于0");
}
if (value > 140)
{
//抛出一个错误,让代码报错并停止
throw new Exception("Age属性的值不能大于140");
}
age = value;
}
}
}
//定义一个Dog 拥有Age Color属性,Age不能小于0 不能大于20 Color必须
是 白 黑 黄 花 这几种颜色之一的char类型
class Dog
{
private int age;
public int Age
{
get
{
return age;
}
set
{
if (value < 0 || value > 20)
{
throw new Exception("Age不在有限的范围内 0-20");
}
age = value;
}
}
//可以使用枚举来限制某个成员变量的值
public enum Ecolor
{
白,
黑,
黄,
花
}
public Ecolor Color;
private char color1;
//成员变量可以直接使用 =xxx 赋予成员变量初始值
private char[] colors = new char[] { '白', '黑', '黄', '花' };
public char Color1
{
get { return color1; }
set
{
if (!colors.Contains(value))
{
throw new Exception("Color属性不再可选范围内");
}
color1 = value;
}
}
}
class Test
{
//有时候我们只需要定义一个公开的属性,不需要操作的拦截
//private string name;
//public string Name { get => name; set => name = value; }
//以上写法比较繁琐,C#提供了一种语法糖,可以简化上面的写法
public string Name { get; set; }
public int Age { get; set; }
//字段设置默认值
private string a = "a的默认值";
//属性的默认值
private string b="b和B的默认值";
public string B { get => b;set=>b = value; }
//属性也可以使用语法糖设置默认值
public string C { get; set; } = "C的默认值";
//当一个属性的访问只有get,没有set的时候,说明这个属性只读
public bool IsAdult
{
//因为属性是依赖访问器进行工作的,因此属性不仅仅可以返回另一个成员变量,
也可以根据现有的数据随时生成一个新的数据
get
{
return Age >= 18;
}
}
public string Info
{
get
{
return $"名字是{Name},年龄是{Age}";
}
}
}
}
构造函数
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 People() { Name = "吴亦凡", Age = 20 };
new People("吴亦凡",9);
}
}
class People
{
public string Name { get; set; }
public int Age { get; set; }
private bool IsAdult;
//在类中可以定义一个和class同名的函数,这个函数将会在创建类的实例化
对象的时候自动执行,我们将它称之为构造函数
//可以看做多态(下期详讲)
public People()
{
Console.WriteLine("构造函数执行了");
//因为构造函数是在对象创建的时候执行的,因此在这里访问不到对象后续赋值
的属性值,访问到的是默认值
Console.WriteLine(Name);
Console.WriteLine(Age);
}
//构造函数本身也是一个函数,可以定义形参接收参数
//构造函数不需要 也不能写返回值
public People(string name, int age)
{
//构造函数的作用:用于在创建对象的时候进行初始化操作
Name = name;
Age = age;
IsAdult = age >= 18;
}
public void Test()
{
if (IsAdult)
{
Console.WriteLine("成年");
}
else
{
Console.WriteLine("未成年");
}
}
}
}
析构函数
C# 不支持显式地调用析构函数,而是由垃圾回收器(Garbage Collector)负责在对象销毁时自动调用析构函数。垃圾回收器会根据对象的生命周期和内存管理策略来确定何时调用析构函数。
当对象没有被任何变量引用时,会被垃圾回收器回收,此时析构函数会执行
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)
{
//类的析构函数是类的一个特殊的成员方法,当一个对象被释放的时候执行
//被释放:C#有垃圾回收机制(GC),当某个数据没有被任何一个变量所引用的时候,
垃圾回收机制就会把这个对象当做垃圾给回收掉
//析构函数:当类的某个对象被当做垃圾回收的时候,这个函数就会自动调用
//析构函数的主要是释放对象的资源,但是析构函数的调用是由垃圾回收器控制的,无法做到显式地调用析构函数,使用析构函数释放资源不是最佳方案(很少使用)
People p1 = new People() { Name="吴凡"};
People p2 = new People() { Name = "罗祥" };
p1 = null;
People p3 = p2;
p3 = null;
p2 = null;
Console.ReadLine();
//强制启动垃圾回收
GC.Collect();
Console.ReadLine();
//定义一个范围,在范围结束的时候处理对象
using (People ps = new People())
{
//ps
}//在范围结束时清理非托管不受GC控制的资源
}
}
//实现接口
class People: IDisposable
{
public string Name { get; set; }
// 析构函数的定义: 一个和类名相同的方法,在方法名前面加上一个~
~People() {
Console.WriteLine($"{Name}即将被回收");
}
void IDisposable.Dispose()
{
throw new NotImplementedException();
}
}
}
静态成员
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)
{
People p1=new People();
//非静态成员的访问: 通过new出来的实例化对象进行访问
p1.Name1 = "吴亦凡";
p1.Test1();
// p1.Name2
//如何访问静态成员呢?
//类名.成员名称 访问非静态成员
People.Name2 = "罗志祥";
People.Test2();
Program.Test();
//静态成员有什么用?
//提供了一种不需要实例化对象,就可以访问类成员的一种方式
//静态成员和非静态成员有什么区别?
//1.访问方式不同
//非静态成员:实例化对象.xxx
//静态成员:类名.xxx
//2.存储的位置不同
//非静态成员:存储在实例化对象上,每一个对象都有一份
//静态成员:存储在类上,所有的实例共享一个成员
}
class People
{
//非静态成员
//非静态属性
public string Name1 { get; set; }
//非静态方法
public void Test1()
{
Console.WriteLine("这是非静态函数Test1");
//在类的非静态方法中,可以访问所有的类成员
Console.WriteLine(Name1);
Console.WriteLine(Name2);
Test2();
}
//静态成员
//静态属性
public static string Name2 { get;set; }
//静态方法
public static void Test2()
{
Console.WriteLine("这是静态函数Test2");
//在类的静态方法中,只能访问静态的类成员
//Console.WriteLine(Name1);
Console.WriteLine(Name2);
// Test1();
Test3();
}
public static void Test3()
{
Console.WriteLine("另外一个静态方法");
}
}
}
静态成员测试
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)
{
Test t1=new Test();
Test t2=new Test();
t1.AddNum();
t2.AddNum();
//静态成员是存储在类上的,所有的实例化对象都共享一个静态成员(独一份)
//无论哪个对象进行了操作,操作的都是同一个数据
t1.getNum();//静态 2 非静态 1
t2.getNum();//静态 2 非静态 1
}
}
class Test
{
public int num = 0;
public void AddNum()
{
num++;
}
public void getNum()
{
Console.WriteLine(num);
}
}
}
常量和只读变量
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _09_常量和只读变量
{
internal class Program
{
static void Main(string[] args)
{
Test t =new Test();
Console.WriteLine(t.a);
//t.a = 5;
Console.WriteLine(Test.c);
}
}
class Test
{
//类的字段可以添加一个readonly 表示 表示这个字段为只读的
//这个字段就不能被构造函数以外的地方修改
public readonly int a = 1;
//静态的readonly 字段 只能在静态的构造函数中被修改
public static readonly int b = 1;
//常量,给字段添加一个const关键字,表示这个字段为常量,不能修改的值
//自动将字段修改为静态的 也只能是静态的
public const int c = 1;
//属性的只读,直接删除set即可,一般属性的只读会搭配一个私有的字段一起使用,
//可以保证一个成员斌量只能在类的内部被修改,不能在外部修改
private string d = "1";
public string D { get => d; }
public Test()
{
a = 2;
//b = 2;
}
static Test()
{
//a = 2;
b = 2;
}
public void Fn()
{
// a = 555;
}
}
}
本期练习题
封装一个类:Aircraft,拥有属性:牌子、型号、颜色、隶属公司、飞行速度、装载人数、飞机类型(大中小(400-200-100)由装载人数自动设置)、当前飞机装载的人数(随机生成)
觉得文章还不错,可以关注,点赞,收藏。主页有C#教程专栏,欢迎订阅!!!