目录
封装
类和对象
类一般声明于namespace语句块中,使用帕斯卡命名法,类是引用对象,在同一语句块中类不能重名。用关键字class 基本语法: class 类名{}
类一般有三种声明方式(如代码)
第一种没有赋值
第二种虽然赋值但是为空
第三种就是创建一个新对象(常用)
namespace Lesson01_封装_类和对象
{
// 类一般声明于namespace语句块中
// 帕斯卡命名法
// 类对象是引用类型
// 在同一语句块中类不能重名
/// <summary>
/// 人
/// </summary>
class Person
{
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Lesson01_封装_类和对象");
Person person1;
Person person2 = null;
Person person3 = new Person();
}
}
}
成员变量和访问修饰符
namespace Lesson02_封装_成员变量和访问修饰符
{
class Person
{
// 特征--成员变量
public string name;
public int age = 0;
// 与结构体不同,类中可以使用自己类型,但不能初始化会导致循环
public Person father;
}
/*
公共和私有与结构体一致
protected 保护的 只有自己内部和子类才可以使用
*/
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Lesson02_封装_成员变量和访问修饰符");
Person p = new();
p.name = "Test";
Console.WriteLine(p.name);
/*
如果类中的变量无初始值,则在new之后会默认分配初始值
有符号无符号浮点: 0
bool: false
char: ''
引用类型: null
*/
// 想要获得一个类型的初始值
// default(类型)
Console.WriteLine(default(byte)); // 0
}
}
}
访问修饰符如下:
1. public 公共的 内外都可以访问
2. private 私有的 只有内部才可以访问
3. protected 保护的 只有内部或子类可以访问
成员变量的格式如下:
访问修饰符 类型 变量名;
其中访问修饰符可以不写,不写默认为私有的,类型可以是任何类型(包括类和结构体)
类中的变量可以有默认值
如果该对象是公共的那么可以用 实例化对象.变量名 来进行使用或者修改
成员方法
namespace Lesson03_封装_成员方法
{
// 成员方法不用加static
class Person
{
public string name = "小明";
public int age;
public Person[] friends;
/// <summary>
/// 说话
/// </summary>
/// <param name="content">内容</param>
public void Speak(string content)
{
Console.WriteLine(content);
}
public void AddFriend(Person p)
{
if (friends == null)
{
friends = [p];
if (p.friends == null || !isIn(this, p.friends))
{
// 将自己成为对方的朋友
p.AddFriend(this);
}
return;
}
Person[] temp = new Person[friends.Length + 1];
for (int i = 0; i < friends.Length; i++)
{
temp[i] = friends[i];
}
temp[^ - 1] = p;
friends = temp;
if (p.friends == null || !isIn(this, p.friends))
{
// 将自己成为对方的朋友
p.AddFriend(this);
}
}
private bool isIn(Person p, Person[] array)
{
for (int i = 0; i < array.Length; i++)
{
if (p == array[i])
{
return true;
}
}
return false;
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Lesson03_封装_成员方法");
// 只有在实例化后才能调用其内部函数
Person p = new Person();
p.name = "Test";
Console.WriteLine(p.name);
Person p2 = new Person();
p2.name = "Test2";
Console.WriteLine(p2.name);
Console.WriteLine("-------");
p2.AddFriend(p);
for (int i = 0; i < p.friends.Length; i++)
{
Console.WriteLine(p.friends[i].name);
}
}
}
}
成员方法的语法如下:
访问修饰符 返回类型 名字(参数列表){}
如果想要实例化对象点出来使用的话则不加static
构造函数和析构函数
namespace Lesson04_封装_构造函数和析构函数
{
class Person
{
public string name;
public int age;
private Person()
{
name = "Test";
age = 10;
}
// 特殊写法: 访问修饰符 名(参数): this(参数)
// 先调用this的函数(即自己的构造函数)再执行代码
public Person(string name, int age): this()
{
this.name = name;
this.age = age;
}
// 析构函数
// 语法: ~类名() {}
// 当引用类型的堆内存被回收后,将调用此函数
/*
垃圾回收(GC)
用遍历在堆(Heap)分配的内存
判断引用类型是否被引用并需要
未被引用的对象就需要被回收
垃圾回收(GC)只支持堆(Heap)上的回收
而栈(Stack)是由自己自动分配回收,不需要GC
*/
~Person()
{
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Lesson04_封装_构造函数和析构函数");
// 如果构造函数中无无参构造函数,则默认的无参构造函数会被顶掉
Person p = new Person("小明", 20);
// 手动触发垃圾回收
GC.Collect();
}
}
}
构造函数基本语法如下:
访问修饰符(一般是public) 类名(参数列表){}
构造函数的使用和结构体一致
其余知识点请参考代码
成员属性
namespace Lesson05_成员属性
{
class Person
{
public string name;
public int age;
private int money;
private string smallName;
/*
语法:
访问修饰符 返回类型 名 { get{} set{} }
*/
// 属性命名使用帕斯卡命名法
public string Name
{
get
{
// 访问Name获取私有变量
return smallName;
}
set
{
// value关键字代表外部赋值的值
smallName = value;
}
}
public int Money
{
// get和set前可以加访问修饰符,不加默认为属性的权限
// get和set可以只有一个
get
{
return Convert.ToInt32(Convert.ToString(money), 2);
}
set
{
// 加密操作
money = int.Parse(Convert.ToString(value < 0 ? 0 : value, 2));
}
}
// 自动属性,类似于声明了一个新的成员变量,并且get和set可以加上访问修饰符
public bool Sex
{
get;
set;
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Lesson05_成员属性");
Person p = new()
{
Name = "小名",
Money = 5000,
Sex = false
};
Console.WriteLine(p.Name);
Console.WriteLine(p.Money);
}
}
}
语法如下:
访问修饰符 类型 属性名(帕斯卡命名法) {get{} set{}}
或者自动属性:
访问修饰符 类型 自动属性名 {get; set;}
其余参考代码
索引器
namespace Lesson06_封装_索引器
{
class Person
{
private List<Person> friends = new();
private int[,] array;
/*
语法:
访问修饰符 返回类型 this[参数列表] { get{} set{} }
*/
// 索引器也可以重载
public int this[int i, int j]
{
get
{
return array[i, j];
}
set
{
array[i, j] = value;
}
}
public Person this[int i]
{
get
{
if (friends == null || friends.Count - 1 < i)
{
return null;
}
return friends[i];
}
set
{
if (friends == null)
{
friends = new List<Person>(1);
friends[0] = value;
}
if (i > friends.Count - 1)
{
friends.Add(value);
return;
}
friends[i] = value;
}
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Lesson06_封装_索引器");
Person p = new();
p[0] = new Person();
Console.WriteLine(p[0]);
p[0, 0] = 10;
}
}
}
语法如下:
访问修饰符 返回类型 this[参数列表] { get{} set{} }
其中get和set与成员属性一致
其余参考代码
静态成员
namespace Lesson07_封装_静态成员
{
class Test
{
// 静态变量
public static int a = 10;
// 普通变量
public int b = 0;
// const类似于static
// 也可以点出来使用,但const必须写在访问修饰符之后,static没有位置的限制
// const只能修饰变量
public const int c = 10;
// 静态函数
public static int CalcInt(int a, int b)
{
// 静态方法中不可以调用非静态成员
return a + b;
}
// 普通函数
public int CalcDoubleNumber(int a)
{
// 但是在普通方法中可以调用静态成员
return a * a;
}
}
static class Temp
{
public static int Test { get; }
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Lesson07_封装_静态成员");
Test t = new();
// 静态变量属性函数由类名.出来使用
Console.WriteLine(Test.a);
Console.WriteLine(Test.CalcInt(10, 3));
}
}
}
关键字: static
其余参考代码
静态类和静态构造函数
namespace Lesson08_封装_静态类和静态构造函数
{
// 静态类无法被实例化,内部只能有静态成员,类似于一个大工具包
static class MathsTools
{
public const double PI = 3.1415926;
public static double CalcCircle(int r) { return r * r * PI; }
public static int Sum(params int[] arr)
{
int sum = 0;
for (int i = 0; i < arr.Length; i++)
{
sum += arr[i];
}
return sum;
}
public static float Sum(float[] array)
{
float sum = 0;
for (int i = 0; i < array.Length; i++)
{
sum += array[i];
}
return sum;
}
}
static class StaticClass
{
public static int a = 100;
public static int b = 100;
// 静态构造函数不能加3p或者参数
// 用于初始化静态成员
// 只会自动调用一次(前提:调用此类中的成员前)
static StaticClass()
{
}
}
class TestClass
{
public static int a = 100;
// 只会自动调用一次(前提:调用此类中的成员前)
// 非静态和静态不冲突,不算重载
static TestClass()
{
}
public TestClass()
{
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Lesson08_封装_静态类和静态构造函数");
}
}
}
参考代码吧
拓展方法
namespace Lesson09_封装_拓展方法
{
static class Tools
{
// 拓展类可以是自定义的类
// 访问修饰符 static 返回值 名(this 拓展类名 参数名, 普通参数列表) {}
// 只能将拓展方法写入静态类中
// 为int拓展了一个普通成员方法
// value代表使用该方法的实例化对象
// 如果拓展方法和为拓展的类名重合,那么只能调用拓展类自带的函数
/// <summary>
/// 将int转为二进制
/// </summary>
/// <param name="value"></param>
public static void Binary(ref this int value)
{
value = int.Parse(Convert.ToString(value, 2));
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Lesson09_封装_拓展方法");
int a = 10;
a.Binary();
Console.WriteLine(a);
}
}
}
语法如下:
访问修饰符 static 返回值 名(this 拓展类名 参数名, 普通参数列表) {}
其余参考代码...
运算符重载
namespace Lesson10_封装_运算符重载
{
static class Tools
{
public static void GetBaseData(this Test value)
{
Console.WriteLine(value.X + "\t" + value.Y);
}
}
class Test
{
public int X { get; set; }
public int Y { get; set; }
// 语法: public static 返回类型 operator 运算符(参数列表) {}
// 可以重载,在进行操作之时必须按照参数顺序来
public static Test operator +(Test t1, Test t2)
{
Test t = new()
{
X = t1.X + t2.X,
Y = t1.Y + t2.Y
};
return t;
}
public static Test operator +(Test t1, int[] arr)
{
Test t = new()
{
X = t1.X + arr[0],
Y = t1.Y + arr[1]
};
return t;
}
/*
可重载的运算符
算数运算符: + - * / % ++ --
逻辑运算符: !
位运算符: & | ^ ~ << >>
条件运算符必须成对出现
条件运算符: < <= > >= == !=
不可重载的 运算符 索引符 强转符 点 赋值 三目运算符
逻辑运算符 : && || [ ] () . = ?:
*/
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Lesson10_封装_运算符重载");
Test t1 = new()
{
X = 10,
Y = 20
};
Test t2 = new()
{
X = 11,
Y = 21
};
Test t3 = t1 + t2;
t3.GetBaseData();
// 可以按照顺序连加
t3 = t1 + [0, 11] + t2;
t3.GetBaseData();
}
}
}
语法:
语法: public static 返回类型 operator 运算符(参数列表) {}
内部类
非重点,就是类中套类
分布类
namespace Lesson11_封装_内部类和分布类
{
// 内部类即类中套类
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public class Body
{
Arm leftArm;
Arm rightArm;
public class Arm
{
public void CatchThing(string thing)
{
// ...
}
}
public Arm this[string value]
{
get
{
switch (value)
{
case "LeftArm":
case "leftArm":
case "LEFTARM":
case "leftarm":
return leftArm;
case "RightArm":
case "rightArm":
case "RIGHTARM":
case "rightarm":
return rightArm;
}
return null;
}
}
}
}
// 分布类将一个类分多部描述
// 关键字: partial
// 成员不能重复
// 分布方法和分布类大同小异
// 只能是私有无返回值不能用out可以有参数
partial class Student
{
public string Name { get; set; }
public int Id { get; set; }
partial void Study();
}
partial class Student
{
partial void Study()
{
// 逻辑内容...
}
public void Speak()
{
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Lesson11_封装_内部类和分布类");
Person p = new();
Person.Body body = new();
Student s = new()
{
Name = "小明"
};
s.Speak();
}
}
}
分布类也不常用稍作了解
继承
继承的基本原则
namespace Lesson13_继承_继承的基本规则
{
class Person
{
public string? name;
public int age;
public Person()
{
name = null;
age = 0;
}
public Person(string? name, int age)
{
this.name = name;
this.age = age;
}
/// <summary>
/// 介绍自己
/// </summary>
public void SaySelf()
{
Console.WriteLine("我叫{0},今年{1}岁", name, age);
}
public void GrowUp()
{
age++;
}
}
class Teather: Person
{
// 职工号
public int number;
// 保护的,只能在内部或子类中使用
protected int testProtected;
// 私有的,只能在内部使用不能在子类或外部中使用
private int testPrivate;
public void SaySelfNumber()
{
testPrivate = 10;
Console.WriteLine("我的工号是:{0}", number);
}
}
class TeathingTeather : Teather
{
// 老师教的科目
public string? subject;
/// <summary>
/// 介绍自己教的课程
/// </summary>
public void SaySelfSubject()
{
Console.WriteLine("我教{0}", subject);
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Lesson13_继承_继承的基本规则");
TeathingTeather tt = new()
{
name = "咸鱼梦想家",
subject = "做饭",
number = 1386413,
age = 18,
};
tt.SaySelf();
tt.SaySelfNumber();
tt.SaySelfSubject();
}
}
}
继承就是儿子继承父亲,儿子保留父亲的特征
一般我们称“父亲”为 父类、基类
“儿子”为 子类、派生类
当然子类有父类的父类······的特征
其余参考代码...
里氏替换原则
里氏替换原则就是父类转子类并且兼容
父类 test = new 子类();
但是因此无法从变量中获取子类的方法所以就有了以下关键字
is
is判断一个对象的值是否是指定的对象
返回值bool
as
将一个对象转换为指定类对象
返回值:指定类型对象
成功返回指定类对象 失败返回null
这个操作称为解引
以下代码供参考...
namespace Lesson14_继承_里氏替换原则
{
class GameObject
{
public int bloodValue;
public int attackValue;
public void Move()
{
Console.WriteLine("移动...");
}
}
class Player : GameObject
{
// 在C#中@写在变量名前可以避免与关键字冲突,@将作为标识符
public void Attack(ref GameObject @object)
{
@object.bloodValue -= attackValue;
Console.WriteLine("玩家攻击...");
}
}
class Monster : GameObject
{
public void Attack(ref GameObject @object)
{
@object.bloodValue -= attackValue;
Console.WriteLine("怪兽攻击...");
}
}
class Boss : GameObject
{
public void Attack(ref GameObject @object)
{
@object.bloodValue -= attackValue;
Console.WriteLine("Boss攻击...");
}
}
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Lesson14_继承_里氏替换原则");
// 里氏替换原则 使用父类容器装载子类
// 变量类型为GameObject
GameObject player = new Player();
GameObject monster = new Monster();
GameObject boss = new Boss();
// 由于类型是GameObject,所以无法调用Player的Attack方法
// player.Attack(); 错误代码
//is和as
//is判断一个对象是否是指定的对象
//返回值bool
//as:将一个对象转换为指定类对象
//返回值:指定类型对象
//成功返回指定类对象 失败返回null
if (player is Player)
{
Console.WriteLine("player是Player类型...");
}
Player p = player as Player;
Console.WriteLine(p is Player);
p.Attack(ref monster);
}
}
}
其余继承和多态待更新中...