1、类和变量介绍
****namespace 类和对象
{
#region 类声明的语法
class Test1
{**
}
#endregion
internal class Program
{
static void Main(string[] args)
{
#region 基础概念
//类是用来描述一类事物的抽象模版
//声明地点:一般声明在namespace中
#endregion
#region 实例化对象
//类的声明和类对象的声明是两个不同概念,类的声明是声明模版,对象是实例化对象。
//类名 变量名;
**Test1 test1;//在栈上分配了空间。
//类名** 变量名 = null;
Test1 test2 = null;//同上,都是栈上分配了空间,堆上没有。
//类名 变量名 = new 类名();
Test1 test3 = new Te**st1();//分配了空间
#endregion**
Test1 test4 = new Test1();
Test1 test5 = test4;
test5 = null;**
}
}
}
2、成员变量和访问修饰符
namespace 成员变量和访问修饰符
{
enum E_Sex
{
man,
woman,
}
#region 成员变量
class Person
{
//成员变量用来描述特征
string name = "半夜微笑狗";
int age;
E_Sex sex;
//不能在class中实例化自己类型的成员变量。
Person grilFriend;
Person[] friend;
}
#endregion
#region 访问修饰符
//private默认修饰符,自己内部才允许调用
//protected 受保护的,允许自己和子类访问
//public 公共的,自己和外部都可以访问
#endregion
internal class Program
{
static void Main(string[] args)
{
#region 成员变量的默认值
#endregion
//打印默认值,引用类型默认是null
Console.WriteLine(default(int)); //默认是0
Console.WriteLine(default(bool));//默认是false
Console.WriteLine(default(string));//null
Console.WriteLine(default(char));//默认是null
Console.WriteLine(default(Person));//默认是null
}
}
}
3、成员方法
namespace 成员方法
{
//成员方法用来描述类的行为
class Student
{
public string name;
public int age;
//成员方法不要加static
public void speak(string str)
{
Console.WriteLine("{0}说{1}", name, str);
}
public bool isAdult()
{
return age >= 18;
}
}
internal class Program
{
static void Main(string[] args)
{
Student s1 = new Student();
s1.name = "李海";
s1.speak("你好");
s1.age = 19;
if (s1.isAdult())
{
Console.WriteLine("可以谈恋爱了");
}
}
}
}
4、构造、析构函数、垃圾回收
namespace 析构和垃圾回收
{
#region 构造函数
class Person
{
public string name;
public int age;
//构造函数用于初始化,实例化对象时会调用,没有构造函数会默认有一个无参构造函数,有参构造函数会顶替掉无参构造函数。
//规则:1、没有返回值 2、与类名相同 3、一般用public
//构造函数:类允许自己声明无参,结构体并不允许
public Person()
{
name = "张未";
age = 15;
}
public Person(string name, int age):this(name)//加了:this()表示先调用this其他的构造函数(根据参数来判定是哪个),比如此时是1个参数为name的构造函数。然后再执行自己的构造函数。
{
Console.WriteLine("2个参数的");
this.name = name;
this.age = age;
}
public Person(string name)
{
this.name = name;
}
}
#endregion
#region 析构函数
class Person
{
~Person()//在工具-选项中选择等宽字体,并且析构函数名与类名相同。
{
GC.Collect();
}
}
#endregion
#region 垃圾回收机制
//GC(垃圾回收机制)只负责堆(heap)上的,引用类型的分配和回收都是通过垃圾回收机制进行的。
//栈上的内存是由系统自动管理的。
//0代 1代 2代
//代是垃圾回收机制中的一种算法(分代算法)
//每次分配都从0代开始,0代满了就会触发垃圾回收机制,清理不被引用的对象,之后将0代搬到1代中并搬迁地址连续并修改地址。
//大对象(85000字节(83kb))通常认为是2代,以便提升性能。
//手动触发GC
//GC.collect();loading过场景时使用。
#endregion
internal class Program
{
static void Main(string[] args)
{
}
}
}
5、成员属性
namespace 成员属性
{
#region 成员属性
class Person
{
private int money;
//get和set方法默认使用属性的修饰符。不能让get和set的访问权限都低于属性,加的访问修饰符要低于属性的修饰符,当然也不能重复。
//get和set方法可以只有一个。
//可以不声明成员变量,直接使用属性,只有get和set,用于外部能得不能改。
public int Money
{
get { return money + 101; }
set
{
Console.WriteLine("set方法已执行");
//可以进行加密操作
money = value - 101;//用value表示传入值。
}
}
}
#endregion
internal class Program
{
static void Main(string[] args)
{
Person person = new Person();
person.Money = 1;
Console.WriteLine(person.Money);
}
}
}
6、索引器
namespace 索引器
{
#region 索引器
class Person
{
////private int[,] data;
//public int this[int i, int j]
//{
// get
// {
// return data[i, j];
// }
// set
// {
// data[i, j] = value;
// }
//}
private int[] arr = new int[10];
//索引器可以让我们访问自定义类中的元素,适合访问数组(记得初始化)可以重载。
public int this[int index]
{
get { return arr[index]; }
set { arr[index] = value; }
}
}
#endregion
internal class Program
{
static void Main(string[] args)
{
Person p = new Person();
//p[0, 0] = 1;
//Console.WriteLine(p[0, 0]);
p[0] = 1;
Console.WriteLine(p[0]);
}
}
}
6、静态成员
namespace 静态成员
{
class Person
{
int sum;
Program p = new Program();
public static void f1()
{
//静态成员方法使用非静态成员需要进行实例化。
Person p = new Person();
Console.WriteLine(p.sum);
}
}
internal class Program
{
int y = 1;
static void Main(string[] args)
{
Person p = new Person();
Person.f1();
}
}
//总结:
//使用static的成员变量、方法、属性等成为静态成员
//使用时用类名.静态成员名使用。
//生命周期:和程序同生共死。
//注意:静态不能直接使用非静态成员,而非静态成员可以直接使用静态成员。
}
7、静态类
namespace 静态类
{
#region 静态类
//概念:使用static关键字修饰的类。来将常用的静态成员写在其中,方便管理。
//只能包含静态成员,不能被实例化。来保证工具类的唯一性。
#endregion
#region 静态构造函数
//特点:1、静态类和普通类都可以有。 2、没有修饰符。 3、不能有参数。 4、只会自动调用一次(第一次使用)。
#endregion
#region 练习题
static class Calculator
{
static float p = 3.14f;
public static float GetRoundArea(float r)
{
return p * r * r;
}
public static float GetRoundCircumference(float r)
{
return 2 * p * r;
}
public static float GetRectArea(float a, float b)
{
return a * b;
}
public static float GetRectCircumference(float a, float b)
{
return a + b;
}
public static float GetModulus(float x)
{
return Math.Abs(x);
}
}
#endregion
internal class Program
{
static void Main(string[] args)
{
int x = (int)Calculator.GetModulus(3);
Console.WriteLine(x);
}
}
}
8、扩展方法
namespace 拓展方法
{
#region 拓展方法
//为现有非静态变量类型 添加 方法
//作用:提升程序的拓展性,比如不需要再在对象中重新写方法,不需要继承来重写方法,给别人封装的类型添加方法。
//基本语法:访问修饰符 static 返回值 函数名(this 拓展类名 参数名, 类型名 参数名, ...)
//特点:静态类中的静态方法,第一个参数 代表拓展的目标,第一个参数前面加this。
#endregion
#region 练习
//扩展整形平方
static class MyClass
{
public static int GetSquare(this int x)
{
return x * x;
}
public static void suicide(this Player player)
{
float hp = 1f;
while(hp > 0)
{
hp = player.TakeDamage(player.Attack());
Console.WriteLine("自杀还剩" + hp + "点血量");
}
Console.WriteLine("该角色已死亡");
}
}
//给玩家类添加自杀方法
class Player
{
string name;
float hp;
float atk;
float def;
public Player(string name, float hp, float atk, float def)
{
this.name = name;
this.hp = hp;
this.atk = atk;
this.def = def;
}
public float Attack()
{
return this.atk;
}
public void Move()
{
Console.WriteLine("移动一格");
}
public float TakeDamage(float atk)
{
hp = hp - atk + def;
if (hp < 0) hp = 0;
Console.WriteLine("剩余:{0} 点血量。", hp);
return hp;
}
}
#endregion
internal class Program
{
static void Main(string[] args)
{
Player p1 = new Player("巨斧战士", 12, 5, 2);
//Player p2 = new Player("精英剑士", 10, 4, 4);
//p1.TakeDamage(p2.Attack());
//p1.TakeDamage(p2.Attack());
p1.suicide();
}
}
}
9、运算符重载
using System.Runtime.InteropServices;
namespace 运算符重载
{
#region 基础
//基础语法:public static 返回类型 operator 运算符(参数列表)
//作用:让类或结构体对象能进行运算。
//注意:条件运算符需要配对出现。
// 一个符号可以进行多次重载。
//不可重载运算符:逻辑与 &&, 逻辑或 ||, 索引符[], 强转符(), 点., 三目运算符? :, 赋值符号=
#endregion
#region 练习
//定义结构体,坐标相等才相等
struct Point
{
public int x;
public int y;
public static bool operator ==(Point p1, Point p2)
{
if(p1.x == p2.x && p1.y == p2.y)
{
return true;
}
return false;
}
public static bool operator !=(Point p1, Point p2)
{
if (p1.x != p2.x || p1.y != p2.y)
{
return false;
}
return true;
}
}
//定义向量类实现运算
class Vector3
{
public int x;
public int y;
public int z;
public Vector3(int x, int y, int z)
{
this.x = x;
this.y = y;
this.z = z;
}
public Vector3() { }
public static Vector3 operator +(Vector3 v1, Vector3 v2)
{
Vector3 v3 = new Vector3();
v3.x = v1.x + v2.x;
v3.y = v1.y + v2.y;
v3.z = v1.z + v2.z;
return v3;
}
public static Vector3 operator -(Vector3 v1, Vector3 v2)
{
Vector3 v3 = new Vector3();
v3.x = v1.x - v2.x;
v3.y = v1.y - v3.y;
v3.z = v1.z - v3.z;
return v3;
}
public static Vector3 operator *(Vector3 v1, int num)
{
Vector3 v3 = new Vector3();
v3.x = v1.x * num;
v3.y = v1.y * num;
v3.z = v1.z * num;
return v3;
}
public override string ToString()
{
return $"{x}, {y}, {z}";
}
}
#endregion
internal class Program
{
static void Main(string[] args)
{
Point p1 = new Point();
Point p2 = new Point();
p1.x = 1;
p1.y = 1;
p2.x = 1;
p2.y = 1;
Console.WriteLine(p1.x == p2.y);
Console.WriteLine("---------------");
Vector3 v1 = new Vector3(1, 2, 3);
Vector3 v2 = new Vector3(3, 2, 1);
Vector3 v3 = v1 + v2;
Console.WriteLine(v3);
}
}
}
10、内部类、分部类
namespace 内部类
{
#region 内部类基础
//内部类使用需要点出外层。
#endregion
#region 分部类基础
//把一个类分成多个部分。
//使用partial关键字。
//作用:扩展程序可以多个文件脚本。
//注意:访问修饰符一致。 不能有重复成员。
//分部方法:1、实现和声明分开。 2、不能加访问修饰符,默认私有。 3、只能在分部类中。 4、返回值是void。 5、可以有参数但不能用out关键字。
#endregion
internal class Program
{
static void Main(string[] args)
{
}
}
}
11、继承基本规则
using System.Xml.Linq;
namespace 继承基础
{
#region 继承基础
//被继承的类叫基类、父类、超类。
//继承的类叫子类、派生类。将拥有父类的所有成员和方法、特征。
//特点:1、单根性:子类只能有一个父类。 2、传递性:子类能间接继承父类的父类。
/*格式:
* class 类名 : 父类名
* {
* }
*/
//子类可以声明相同成员名称来覆盖父类成员,但不推荐。可使用new关键字 public new string str;
#endregion
#region 练习
class Person
{
protected string name;
protected int age;
protected void Speak()
{
Console.WriteLine($"我叫{name}, 我今年{age}岁了");
}
}
class Soldier : Person
{
public void SetProfile(string name, int age)
{
this.name = name; // 子类内部可访问
this.age = age;
}
public string Name
{
get { return name; }
set
{
this.name = value;
}
}
public int Age
{
get { return age; }
set
{
this.age = value;
}
}
public void Attck()
{
Speak();
Console.WriteLine("进攻");
}
}
#endregion
internal class Program
{
static void Main(string[] args)
{
Soldier sd = new Soldier();
sd.Name = "123";
sd.Age = 12;
sd.Attck();
}
}
}
12、里氏替换原则
namespace 里氏替换
{
#region 基础概念
//面相对象七大原则之一。
//概念:父类出现的地方都可以使用子类替换。
//语法表现:父类容器装子类对象。
//作用:方便进行对象管理和存储。
//注意:不能用子类容器装父类对象。
#endregion
#region is和as
//类对象 is 类型 返回一个bool true或false
//类对象 as 类型 转换一个类型 指定类型或null
#endregion
#region 练习
class Monster
{
}
class Boss : Monster
{
public void Skill()
{
Console.WriteLine("巨力猛击");
}
}
class Goblin : Monster
{
public void Attack()
{
Console.WriteLine("普通攻击");
}
}
#endregion
internal class Program
{
static Monster GetMonster()
{
Random r = new Random();
int x = r.Next(0, 2);
Monster monster;
switch (x)
{
case 0:
monster = new Boss();
break;
case 1:
monster = new Goblin();
break;
default:
throw new InvalidOperationException("Unexpected random value");
}
return monster;
}
static void Main(string[] args)
{
Monster[] monster = new Monster[10];
for(int i = 0; i < 10; i++)
{
monster[i] = GetMonster();
}
for (int i = 0; i < 10; i++)
{
if (monster[i] is Boss)
{
(monster[i] as Boss).Skill();
}
else
{
(monster[i] as Goblin).Attack();
}
}
}
}
}
13、继承中的构造函数
using System.Threading.Tasks.Dataflow;
namespace 继承构造函数
{
internal class Program
{
#region 基础概念
//声明子类对象,先执行父类构造,后子类构造,父类的父类会更早执行。
//使用base关键字可以使用父类
//父类的无参构造很重要,子类实例化会默认执行父类无参构造函数。
//如果子类默认调用的父类构造(无参构造)被顶掉了。那么可以:public 子类名(参数名) : base(参数名){}
#endregion
#region 练习
//工人基类,程序、策划、美术继承。实力化他们。
class Worker
{
protected string job;
protected string content;
public Worker(string job, string content)
{
this.job = job;
this.content = content;
Console.WriteLine($"1工人叫{this.job}, 工作内容是{this.content}");
}
public void Work()
{
Console.WriteLine($"我的工作是{job},工作内容是{content}");
}
}
class Programmer : Worker
{
public Programmer() : base("123", "555")
{
this.job = job;
this.content = content;
Console.WriteLine($"2工人叫{base.job}, 工作内容是{base.content}");
}
}
#endregion
static void Main(string[] args)
{
//Worker w = new Worker("程序", "编写代码");
//w.Work();
Programmer p = new Programmer();
}
}
}
14、万物之父和装箱、拆箱
namespace 万物之父
{
#region 基础概念
//关键字:object
//概念:他是所有类型的基类
//作用:利用里氏替换原则,用来装所有类型。
// 可以表示不确定类型,作为参数类型。
//使用时,引用类型可以用as,值类型用()强转。
//装箱:引用类型存储值类型,栈内存会迁移到堆内存中。
//拆箱:把引用类型存储的值取出,堆内存迁移到栈内存中。
//好处:不确定类型也能存储和传递;坏处:内存迁移会消耗性能。
#endregion
#region 实例
class Father
{
}
class Son : Father;
#endregion
internal class Program
{
static void Main(string[] args)
{
Object son = new Son();
Console.WriteLine(son is Object);
//装箱、拆箱
object o = 4;
int x = (int)o;
}
}
}
15、封装类
namespace 密封类
{
#region 基础概念
//关键字:sealed
//作用:让类无法被继承
//意义:提升面相对象程序的安全性、规范性、结构性。
#endregion
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
}
16、多态
using System.Security.Cryptography;
namespace 多态
{
#region 基础
//多态:让同类型对象执行同一方法有不同的表现。
//解决:让同一对象有唯一行为特征。不用转换类型。
//vob:v:virtual 虚函数,用在父类方法上。 o:override 重写,用在与虚函数对应的子类方法上。b:base 父类,用来保留base.方法名保留父类方法。
#endregion
#region 练习
//三种不同鸭子的叫声
class Duck
{
public virtual void Cry()
{
Console.WriteLine("嘎嘎");
}
}
class WoodDuck : Duck
{
public override void Cry()
{
Console.WriteLine("吱吱");
}
}
class RubberDuck : Duck
{
public override void Cry()
{
Console.WriteLine("唧唧");
}
}
//不同员工上班打卡
class Staff
{
public virtual void ClockIn()
{
Console.WriteLine("9点");
}
}
class Manager : Staff
{
public override void ClockIn()
{
Console.WriteLine("11点");
}
}
class Programmer : Staff
{
public override void ClockIn()
{
Console.WriteLine("不用打卡");
}
}
#endregion
internal class Program
{
static void Main(string[] args)
{
Duck d1 = new WoodDuck();
d1.Cry();//>>吱吱
Duck d2 = new RubberDuck();
d2.Cry();//>>唧唧
Staff s1 = new Staff();
s1.ClockIn();//>>9点
Staff s2 = new Manager();
s2.ClockIn();//>>11点
Staff s3 = new Programmer();
s3.ClockIn();//>>不用打卡
}
}
}
17、抽象类和抽象方法
namespace 抽象类
{
#region 抽象类基础
//概念:被关键字abstract修饰的类
//特点:1、不能实例化。2、可有抽象方法。3、继承抽象类必须重写抽象方法。
#endregion
#region 抽象方法基础
//概念:abstract修饰的方法
//特点:1、没有方法体。 2、不能是私有的。 3、继承后必须override重写。 4、只能在抽象类中。
#endregion
#region 练习
//证明继承的子类必须重写,孙子类也可以重写但子类必须先重写。
abstract class Fruit
{
public abstract void eat();
}
class Apple : Fruit
{
public override void eat()
{
Console.WriteLine("1");
}
}
class SupperApple : Apple
{
public override void eat()
{
base.eat();
Console.WriteLine("1");
}
}
//动物抽象类实现
abstract class Animal
{
abstract public void Cry();
}
class Person : Animal
{
public override void Cry()
{
Console.WriteLine("人叫");
}
}
#endregion
internal class Program
{
static void Main(string[] args)
{
Animal animal = new Person();
animal.Cry();
}
}
}
18、接口
namespace 接口
{
#region 接口的概念
//接口是行为的规范,接口继承可以看做是对某一类行为的抽象,两个无关系的类也可能会继承同一接口。
//接口是一种自定义类型。
//使用关键字interface
//接口声明规范:
//1、不包含成员变量,只有属性、方法、索引器、事件。
//2、成员不能被实现,注意在C#8.0后可以实现方法,且子类不用实现,子类若重写则不用写Virtual加Override也会按照子类执行。
//3、成员默认是public修饰符,不能是private。
//4、接口不能继承类,但能继承另一个接口。
//特点:
//类可以继承多个接口。
//继承接口后必须实现方法,可以在方法实现时添加virtual,来让子类可以重写。
//接口不能被实例化。
//接口继承时不用实现,类继承时会实现。
/*
* interface I接口名
* {
* }
*/
//显式实现接口就是 接口名.方法名 然后去实现。用于不同接口的相同方法实现。
#endregion
#region 练习1
//实现登记方法。
interface Register
{
void Register();
}
class Person : Register
{
public void Register()//注意类中默认为成员的修饰符为private,而接口中为public范围更大,要加public
{
Console.WriteLine("人登记");
}
}
class Car : Register
{
public void Register()
{
Console.WriteLine("车登记");
}
}
class House : Register
{
public void Register()
{
Console.WriteLine("房登记");
}
}
#endregion
#region 练习2:飞行与鸟
abstract class SomeAnimal//动物抽象
{
protected abstract void Walk();
}
abstract class Bird : SomeAnimal//定义鸟抽象类
{
}
interface Fly//定义飞行接口
{
void Fly();
}
interface Swim//游泳接口
{
void Swim();
}
class Sparrow : Bird, Fly//麻雀类
{
protected override void Walk()
{
Console.WriteLine("麻雀跳越");
}
public void Fly()
{
Console.WriteLine("麻雀飞翔");
}
}
#endregion
#region 练习3:传输数据
interface USB
{
void Transmission();
}
abstract class StorageDevice : USB
{
abstract public void Transmission();
}
class U : StorageDevice
{
public override void Transmission()
{
Console.WriteLine("U盘传输");
}
}
#endregion
internal class Program
{
static void Main(string[] args)
{
Register r1 = new Car();
r1.Register();
USB uSB = new U();
uSB.Transmission();
}
}
}
19、密封方法
#region 基础
//密封方法可以让虚方法和抽象方法不能再被子类的子类重写。
//通常在override前面使用。
#endregion
20、命名空间
using MySapce;
using ExSpace;
using UI;
namespace 命名空间
{
#region 基本概念
//1、命名空间是用来组织和重用代码。类似于工具包,类就是其中的工具。
/*基本语法:
* namaspace 空间名
* {
* }
*/
//命名空间可以分成几次写。
//使用不同的命名空间中的东西需要先引用using 命名空间名 或 指明出处 命名空间名.成员名
//使用不同命名空间的同名成员时会报错。这时候需要指明出处。
//命名空间可以包裹命名空间。
#endregion
internal class Program
{
static void Main(string[] args)
{
//Myclass1 c = new Myclass1();//会报错
UI.Image i1 = new Image();
Graph.Image i2 = new Graph.Image();
}
}
}
#region 练习
//using作用是引用其他命名空间。
namespace UI
{
class Image
{
public Image()
{
Console.WriteLine("UI");
}
}
}
namespace Graph
{
class Image
{
public Image()
{
Console.WriteLine("Graph");
}
}
}
#endregion
namespace ExSpace
{
struct Myclass1
{
}
}
namespace MySapce
{
class Myclass1
{
}
}
21、万物之父的方法
using System.Xml.Linq;
namespace 万物之父中的方法
{
#region 静态方法
//Equals:判断两边是否相等。引用类型判断的是地址是否相等。
//ReferenceEquals:判断引用类型是否相等,值类型判断始终为false。
#endregion
#region 成员方法
//GetType:作用:获取对象运行时的类型Type,和反射相关。
//MemberWiseClone:返回一个浅拷贝对象。新对象中的引用变量和老对象中一致,改变会影响老的引用类型。但类中的值类型不会变。
#endregion
#region 虚方法
//可以重写自己的Equals和GetHashCode
//ToString:重写转字符串。
#endregion
#region 练习
//打印玩家类属性
class Player
{
string name;
int hp;
int atk;
int def;
int dod;
public Player()
{
}
public Player(string name, int hp, int atk, int def, int dod)
{
this.name = name;
this.hp = hp;
this.atk = atk;
this.def = def;
this.dod = dod;
}
public override string ToString()
{
return $"玩家{name}, 血量{hp}, 攻击力{atk}, 防御力{def}, 闪避率{dod}";
}
}
//克隆体,不受影响
class Monster
{
public int hp = 25;
public int atk = 5;
public int def = 15;
public int skillId = 55;
public Monster Clone()
{
return this.MemberwiseClone() as Monster;
}
public override string ToString()
{
return $"血量{hp}, 攻击力{atk}, 防御力{def}, 技能id{skillId}";
}
}
#endregion
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine(object.Equals(1, 1));
Console.WriteLine(Object.ReferenceEquals(1, 1));//默认直接也能使用这两个方法,因为类是object的派生类。
Player p1 = new Player("战士", 50, 3, 5, 10);
Console.WriteLine(p1.ToString());
Monster A = new Monster();
Monster B = A.Clone();
Console.WriteLine(A.ToString());
Console.WriteLine(B.ToString());
B.hp = 2;
Console.WriteLine(A.ToString());
Console.WriteLine(B.ToString());
}
}
}
22、string
namespace String
{
internal class Program
{
#region 基本
//string本质是char数组
//转换char数组
char[] charArr = "123".ToCharArray();
#endregion
static void Main(string[] args)
{
string s = "123456123456";
//获取位置
Console.WriteLine(s[1]);
//获取长度
Console.WriteLine(s.Length);
//拼接,Format通常是用于更复杂的处理
Console.WriteLine(string.Format("123{0}", s));
//正向查找元素位置,没有返回-1,可以查找字符串。
Console.WriteLine(s.IndexOf("345"));
//反向查找位置,寻找最后面的元素,并返回正向下标。无返回-1
Console.WriteLine(s.LastIndexOf("456"));//》9
//删除,会删除下标出的元素,及以后的所有元素。会返回一个新字符串。注意不会改变原来的。
//也能使用Remove(指定开始位置, 个数)来进行删除。
Console.WriteLine(s.Remove(3));
//替换指定字符串
Console.WriteLine(s.Replace("123", "汪汪汪"));//>>汪汪汪456汪汪汪456
//大小写转换
Console.WriteLine("abc".ToUpper());//转大写
Console.WriteLine("A".ToLower());//转大写
//截取,包含指定位置开始,及其后面。也能指定个数在第二个参数。注意越界。
Console.WriteLine(s.Substring(6));
//切割,以特定字符或串来分隔并返回字符串数组。
Console.WriteLine("999123888".Split("999")[1] + "------");//>>123888------
#region 练习
//练习截取和替换
string str = "123".Substring(1, 2);
Console.WriteLine(str);
Console.WriteLine("12345".Replace("45", "123"));
//1|2|3|4|5|6|7的分割变化
str = "1|2|3|4|5|6|7";
string[] sArr = str.Split("|");
str = "";
for(int i = 1; i < sArr.Length; i++)
{
str += sArr[i] + "|";
}
str += "8";
Console.WriteLine(str);
//String和string、Int32和int、Int16和short、Int64和long他们的区别是什么 ?
//属于相同的关系,后者是前者的别称。
/*string str = null; str = "123";
string str2 = str; str2 = "321".str2 += "123";
请问,上面这段代码,分配了多少个新的堆空间=3个*/
//编写一个函数,将输入的字符串反转。不要使用中间商,你必须原地修改输入数组。交换过程中不使用额外空间比如:
str = "hello";
Console.Write("开始输出:");
for(int i = 0; i < 5; i++)
{
sArr[i] = str[4 - i].ToString();
Console.Write(sArr[i] + ",");
}//开始输出:o,l,l,e,h,
#endregion
}
}
}
23、stringBuilder
using System.Text;
namespace _StringBuilder
{
internal class Program
{
static void Main(string[] args)
{
#region StringBuilder
//用于经常修改字符串,它不会创建新字符串来提高性能。
//需要引用命名空间。
StringBuilder stringBuilder = new StringBuilder("123", 16);//存入123,并定义长度为16
//StringBuilder有初始容量16。不够时会增加。
//获取容量
Console.WriteLine(stringBuilder.Capacity);//》16
//获取字符串长度
Console.WriteLine(stringBuilder.Length);
#endregion
#region 增删查改替换
//增加
stringBuilder.Append("123");//末尾增加
Console.WriteLine(stringBuilder);//>>123123
stringBuilder.AppendFormat("{0}", 1);
Console.WriteLine(stringBuilder);//>>1231231
//插入
stringBuilder.Insert(1, "哈哈哈");//Insert(索引, string串);
Console.WriteLine(stringBuilder);//1哈哈哈231231
//删除
stringBuilder.Remove(0, 1);
Console.WriteLine(stringBuilder);//>>哈哈哈231231
//清空
stringBuilder.Clear();
Console.WriteLine(stringBuilder);//>>
//查找:stringBuilder[1];
//改
stringBuilder.Append("Hello");
stringBuilder[0] = 'h';
Console.WriteLine(stringBuilder);//>>hello
//替换
stringBuilder.Replace('h', 'H');
Console.Write(stringBuilder);//》Hello
if(stringBuilder.Equals("Hello"))
{
Console.WriteLine("相等");
}
#endregion
//string和StringBuilder区别
/*
* string更容易产生垃圾,每次修改都会。
* string方法更多。
*/
//怎么优化内存
//1、如何节约内存:少new对象。少产生垃圾
//2、合理使用static
//3、使用string和StringBuilder
}
}
}
24、类和结构体的区别
namespace 结构体和类区别
{
#region 概述
//结构体是值类型,存储在栈上。而类是引用类型,存储在堆上。
//结构体没有继承和多态的,只有封装,所以不能使用保护修饰符。
#endregion
#region 细节
//结构体声明时不能赋值
//结构体不能声明无参构造函数
//结构体声明有参构造函数无参构造不会被顶掉
//结构体不能声明析构函数,类可以
//结构体不能被继承
//结构体需要再构造函数中初始化
//结构体不能不能用static修饰,类可以
//结构体内不能声明自己的类型,类可以
struct Person
{
int age;
}
#endregion
#region 特别之处
//结构体能继承接口,因为接口是行为的抽象。
#endregion
#region 使用
//需要继承用类,如玩家,怪物。数据的集合用结构体,如坐标。
//
#endregion
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
}
25、接口和抽象类区别
namespace 接口和抽象类
{
internal class Program
{
static void Main(string[] args)
{
#region 相同点
/* 1、都可以被继承
* 2、都不能直接实例化
* 3、子类必须实现方法
* 4、都遵守里式替换原则
*/
#endregion
}
}
#region 不同点
//抽象类中可以有构造方法,接口没有
abstract class Animal
{
int id;
Animal(int id)
{
this.id = id;
}
void fun()
{
Console.Write(1);
}
}
interface Fly
{
abstract void funt();
void func();
}
//抽象类只能被单一继承,接口被类继承多个。
//抽象类中可以有成员变量、成员方法、虚方法、抽象方法、静态方法并且他们可以被实现;接口中只能有没有被实现的方法。(8.0以后接口中也能有实现了的方法)
//抽象类可以使用访问修饰符,接口建议不写,默认为public。
//实现抽象方法需要加override,实现接口中的方法不用加override。
#endregion
#region 使用
//表示对象的抽象用抽象类,行为用接口。
#endregion
}
26、面相对象七大原则
七大原则实现目标:高内聚、低耦合。
使程序模块的可重用性、移植性加强。
1、单一职责原则:类应该专注于单一功能。
2、开闭原则:对扩展开放,对修改关闭。
3、里式替换原则:用父类装载子类。
4、依赖倒转原则:不依赖于具体事物,而依赖于其抽象。
5、迪米特原则:一个对象应该少于其他类发生关联。
6、接口分离原则:一个接口应该只提供一个功能,让其他想实现什么就继承什么接口,而非多个功能在一个接口中。
7、合成复用原则:尽量使用对象组合,而不是继承来达到复用目的。继承时强耦合,组合是弱耦合。
27、贪吃蛇
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.Lesson2;
namespace 贪吃蛇.Lesson1
{
enum E_SceneType
{
Begin,
game,
end,
}
class Game
{
public const int w = 80;
public const int h = 20;
public static ISceneUpdate sceneUpdate;
public Game()
{
Console.CursorVisible = false;
Console.SetWindowSize(w, h);
Console.SetBufferSize(w, h);
ChangeScene(E_SceneType.Begin);
}
public void Start()
{
while (true)
{
if(sceneUpdate != null)
{
sceneUpdate.Update();
}
}
}
public static void ChangeScene(E_SceneType type)
{
Console.Clear();
switch (type)
{
case E_SceneType.Begin:
sceneUpdate = new BeginScene();
break;
case E_SceneType.game:
sceneUpdate = new GameScene();
break;
case E_SceneType.end:
sceneUpdate = new EndScene();
break;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 贪吃蛇.Lesson1
{
interface ISceneUpdate
{
public void Update();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.Lesson1;
namespace 贪吃蛇.Lesson2
{
abstract class BeginAndEndScene : ISceneUpdate
{
protected int nowIndex = 0;
protected string title;
protected string option1;
public abstract void EnterJDo();
public void Update()
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.SetCursorPosition(Game.w / 2 - title.Length, 3);
Console.Write(title);
Console.ForegroundColor = nowIndex == 0 ? ConsoleColor.Red : ConsoleColor.Yellow;
Console.SetCursorPosition(Game.w / 2 - option1.Length, 8);
Console.Write(option1);
Console.ForegroundColor = nowIndex == 1 ? ConsoleColor.Red : ConsoleColor.Yellow;
Console.SetCursorPosition(Game.w / 2 - 4, 10);
Console.Write("结束游戏");
switch (Console.ReadKey(true).Key)
{
case ConsoleKey.W:
--nowIndex;
if(nowIndex < 0)
{
nowIndex = 0;
}
break;
case ConsoleKey.S:
++nowIndex;
if(nowIndex > 1)
{
nowIndex = 1;
}
break;
case ConsoleKey.J:
EnterJDo();
break;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.Lesson1;
namespace 贪吃蛇.Lesson2
{
class BeginScene : BeginAndEndScene
{
public BeginScene()
{
title = "贪吃蛇";
option1 = "进入游戏";
}
public override void EnterJDo()
{
if(nowIndex == 0)
{
Game.ChangeScene(E_SceneType.game);
}
else
{
Environment.Exit(0);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.Lesson1;
namespace 贪吃蛇.Lesson2
{
class EndScene : BeginAndEndScene
{
public EndScene()
{
title = "游戏结束";
option1 = "回到开始";
}
public override void EnterJDo()
{
if(nowIndex == 0)
{
Game.ChangeScene(E_SceneType.Begin);
}
else
{
Environment.Exit(0);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.Lesson1;
using 贪吃蛇.Lesson4;
using 贪吃蛇.Lesson5;
using 贪吃蛇.Lesson6;
namespace 贪吃蛇.Lesson2
{
class GameScene : ISceneUpdate
{
Map map;
Snake snake;
Food food;
int count = 0;
public GameScene()
{
map = new Map();
snake = new Snake();
food = new Food(snake);
}
public void Update()
{
if(count % 40000 == 0)
{
map.Draw();food.Draw();
snake.Move();
snake.Draw();
if (snake.Die(map))
{
Game.ChangeScene(E_SceneType.end);
}
snake.CheckEatFood(food);
count = 0;
}
if (Console.KeyAvailable)
{
switch (Console.ReadKey(true).Key)
{
case ConsoleKey.W:
snake.ChangeDir(E_MoveType.up);
break;
case ConsoleKey.S:
snake.ChangeDir(E_MoveType.down);
break;
case ConsoleKey.A:
snake.ChangeDir(E_MoveType.left);
break;
case ConsoleKey.D:
snake.ChangeDir(E_MoveType.right);
break;
}
}
count++;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 贪吃蛇.Lesson3
{
abstract class GameObject : IDraw
{
public Position position;
public abstract void Draw();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 贪吃蛇.Lesson3
{
interface IDraw
{
public void Draw();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 贪吃蛇.Lesson3
{
struct Position
{
public int x;
public int y;
public Position(int x, int y)
{
this.x = x;
this.y = y;
}
public static bool operator ==(Position p1, Position p2)
{
if(p1.x == p2.x && p1.y == p2.y)
{
return true;
}
return false;
}
public static bool operator !=(Position p1, Position p2)
{
if(p1.x == p2.x && p1.y == p2.y)
{
return false;
}
return true;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.Lesson1;
using 贪吃蛇.Lesson3;
using 贪吃蛇.Lesson6;
namespace 贪吃蛇.Lesson4
{
class Food : GameObject
{
public Food(Snake snake)
{
RandomPos(snake);
}
public override void Draw()
{
Console.SetCursorPosition(position.x, position.y);
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("¤");
}
//随机事物并判断重合(蛇)
public void RandomPos(Snake snake)
{
Random random = new Random();
int x = random.Next(2, Game.w / 2 - 2) * 2;
int y = random.Next(1, Game.h - 3);
position = new Position(x, y);
if (snake.CoincideFood(position))
{
RandomPos(snake);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.Lesson3;
enum E_SnakeType
{
Head,
Body,
}
namespace 贪吃蛇.Lesson4
{
class SnakeBody : GameObject
{
E_SnakeType snakeType;
public SnakeBody(E_SnakeType snakeType, int x, int y)
{
this.snakeType = snakeType;
position = new Position(x, y);
}
public override void Draw()
{
Console.SetCursorPosition(position.x, position.y);
Console.ForegroundColor = snakeType == E_SnakeType.Head ? ConsoleColor.Yellow : ConsoleColor.Green;
Console.WriteLine(snakeType == E_SnakeType.Head ? "●" : "◎");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.Lesson3;
namespace 贪吃蛇.Lesson4
{
class Wall : GameObject
{
public Wall(int x, int y)
{
position = new Position(x, y);
}
public override void Draw()
{
Console.SetCursorPosition(position.x, position.y);
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("▓");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.Lesson1;
using 贪吃蛇.Lesson3;
using 贪吃蛇.Lesson4;
namespace 贪吃蛇.Lesson5
{
class Map : IDraw
{
public Wall[] wall;
int index;
public Map()
{
index = 0;
wall = new Wall[Game.w + (Game.h - 3) * 2];
for(int i = 0; i < Game.w; i+=2)
{
wall[index] = new Wall(i, 0);
index++;
wall[index] = new Wall(i, Game.h - 2);
index++;
}
for(int i = 1; i < Game.h - 2; i++)
{
wall[index] = new Wall(Game.w - 2, i);
index++;
wall[index] = new Wall(0, i);
index++;
}
}
public void Draw()
{
for(int i = 0; i < wall.Length; i++)
{
wall[i].Draw();
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.Lesson3;
using 贪吃蛇.Lesson4;
using 贪吃蛇.Lesson5;
//移动枚举
enum E_MoveType
{
up,
down,
left,
right,
}
namespace 贪吃蛇.Lesson6
{
class Snake : IDraw
{
public SnakeBody[] bodys;
public int bodyNum;
E_MoveType moveType;
public Snake()
{
bodys = new SnakeBody[200];
bodys[0] = new SnakeBody(E_SnakeType.Head, 40, 10);
bodyNum = 1;
moveType = E_MoveType.right;
}
public void Draw()
{
for(int i = 0; i < bodyNum; i++)
{
bodys[i].Draw();
}
}
public void Move()
{
SnakeBody lastBody = bodys[bodyNum - 1];
Console.SetCursorPosition(lastBody.position.x, lastBody.position.y);
Console.WriteLine(" ");
if (bodyNum > 1)
{
for (int i = bodyNum - 1; i > 0; i--)
{
bodys[i].position = bodys[i - 1].position;
}
}
switch (moveType)
{
case E_MoveType.up:
bodys[0].position.y--;
break;
case E_MoveType.down:
bodys[0].position.y++;
break;
case E_MoveType.left:
bodys[0].position.x -= 2;
break;
case E_MoveType.right:
bodys[0].position.x += 2;
break;
}
}
//转换方向
public void ChangeDir(E_MoveType e_Move)
{
if(this.moveType == e_Move ||
bodyNum > 1 && (
this.moveType == E_MoveType.up && e_Move == E_MoveType.down ||
this.moveType == E_MoveType.down && e_Move == E_MoveType.up ||
this.moveType == E_MoveType.left && e_Move == E_MoveType.right ||
this.moveType == E_MoveType.right && e_Move == E_MoveType.left))
{
return;
}
this.moveType = e_Move;
}
//撞墙、身体逻辑。
public bool Die(Map map)
{
for(int i = 0; i < map.wall.Length; i++)
{
if (bodys[0].position == map.wall[i].position)
{
return true;
}
}
for (int i = 1; i < bodyNum; i++)
{
if (bodys[0].position == bodys[i].position)
{
return true;
}
}
return false;
}
//是否与食物重合
public bool CoincideFood(Position position)
{
for(int i = 0; i < bodyNum; i++)
{
if(position == bodys[i].position)
{
return true;
}
}
return false;
}
public void CheckEatFood(Food food)
{
if (bodys[0].position == food.position)
{
food.RandomPos(this);
AddBody();
}
}
//增加身体
void AddBody()
{
bodys[bodyNum] = new SnakeBody(E_SnakeType.Body, bodys[bodyNum - 1].position.x, bodys[bodyNum - 1].position.y);
bodyNum++;
}
}
using 贪吃蛇.Lesson1;
using 贪吃蛇.Lesson6;
namespace 贪吃蛇
{
internal class Program
{
static void Main(string[] args)
{
Game game = new Game();
game.Start();
}
}
}