本文适合有一定C#基础的初学者。
设计模式
含义:帮助我们降低对象之间的耦合度常用的方法称为设计模式。使用设计模式是为了可重用代码,让代码更容易被其他人所理解,保证代码可靠性,使代码编制真正工程化,这是软件工程的基石。
分类:
创建型模式:工厂方法模式、抽象工厂模式、单例模式、建造者模式、组合模式、原型模式。
结构型模式:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
单例模式
含义:一个类只有一个实例,只在内部实例一次,外部无法实例化,全局唯一。一般应用于各种管理器,如角色管理器、声音管理器,场景管理器。
public class MySingleton
{
private static MySingleton __instance;
public static MySingleton instance{
get{
if(__instance == null){
__instance = new MySIngleton();
}
}
}
public MySingleton(){
Debug.Log("执行构造函数");
}
public void Show(){
Debug.Log("show");
}
}
MySingleton.instance.Show();
观察者模式
含义:可称为发布/订阅模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象(多播委托)。主题对象发生变化时,它们能够自动更新自己,通常用作实现事件处理系统。
Using System;
using UnityEngine;
public class Animal{
protected string Name;
public Animal(string name){
this.Name = name;
}
public virtual void Run(){
}
}
public class Cat:Animal{
public Action actions; //发布者
public Cat(string name):base(name){
}
public void Coming(/*MouseA mouseA,MouseB mouseB,MouseC mouseC*/){
Debug.Log(Name + "猫来了");
//mouseA.Run();
//mouseB.Run();
//mouseC.Run();
this.Run();
if(actions!= null){
actions();
}
}
public override void Run(){
Debug.Log(Name + "追老鼠");
}
}
public class Mouse:Animal{
public Mouse(string name,Cat cat):base(name){
cat.actions += this.Run; //订阅者
}
public override void Run(){
Debug.Log(Name + "老鼠跑");
}
}
public class Visit:monoBehaviour{
void Start(){
Cat cat = New Cat("小野猫");
Mouse mouseA = new Mouse("mouseA",cat);
Mouse mouseB = new Mouse("mouseB",cat);
Mouse mouseC = new Mouse("mouseC",cat);
// 在老鼠数量不确定的情况下,这样的设计是不合理的
//cat.Coming(mouseA,mouseB,mouseC);
// 这样合理
cat.Coming();
}
}
简单工厂/工厂/抽象工厂
简单工厂模式:又叫静态工厂方法模式,由一个工厂对象决定创建出哪一种产品类的实例。只生产一个品类的产品,在工厂中动态创建。
工厂模式:避免简单工厂模式中,新增产品品牌(类型)时,直接修改工厂类。通过多个工厂创建不同的产品。
抽象工厂模式:解决系列产品问题,生产多种产品。
简单工厂模式:
namespace Factor{
public abstract class AbstractMouse{
public abstract void Print();
}
}
using UnityEngine;
namespace Factor{
public class DellMouse: AbstractMouse{
public override void Print(){
Debug.Log("生产了一个Dell鼠标");
}
}
}
using UnityEngine;
namespace Factor{
public class HpMouse: AbstractMouse{
public override void Print(){
Debug.Log("生产了一个Hp鼠标");
}
}
}
namespace Factor{
public class SampleFactor{
public AbstractMouse CreateMouse(MouseType emMouseType){
AbstractMouse mouse = null;
switch(emMouseType){
case MouseType.HpMouse:
mouse = new HpMouse();
break;
case MouseType.DellMouse:
mouse = new DellMouse();
break;
default:
break;
}
return mouse;
}
}
}
using UnityEngine;
using Factor;
public enum MouseType{
None,
DellMouse,
HpMouse,
}
public class FactorMain:MonoBehaviour{
void Start(){
RunNormal();
RunSampleFactor();
}
void RunNormal(){
DellMouse dellMouse = new DellMouse();
dellMouse.Print();
HpMouse hpMouse = new HpMouse();
hpMosue.Print();
}
// 外界不需要关注具体的子类对象
void RunSampleFactor(){
SampleFactor factor = new SampleFactor();
AbstactMouse dellMouse = factor.CreateMouse(MouseType.DellMouse);
dellMouse.Print();
AbstactMouse hpMouse = factor.CreateMouse(MouseType.HpMouse);
hpMouse.Print();
}
}
工厂模式:
namespace Factor{
public abstract class FactorBase{
public abstract AbstractMouse CreateMouse();
}
}
namespace Factor{
public class DellFactor:FactorBase{
public override AbstractMouse CreateMouse(){
return new DellMouse();
}
}
}
namespace Factor{
public class HpMouse:FactorBase{
public override AbstractMouse CreateMouse(){
return new HpMouse();
}
}
}
public class FactorMain:MonoBehaviour{
void Start(){
RunFactor();
}
--snip--
void RunFactor(){
DellFactor dellFactor = new DellFactor();
AbstractMouse dellmouse = dellFactor.CreateMouse();
dellMouse.Print();
HpFactor hpFactor = new HpFactor();
AbstractMouse hpmouse = hpFactor.CreateMouse();
hpmouse.Print();
}
}
工厂模式的好处在于当新增一个类的时候我们不会对原来的代码进行修改,只新增类本身及其工厂。
抽象工厂模式: 可以生产多个类别产品。
namespace Factor{
public abstract class AbstractKeyBoard{
public abstract void Print();
}
}
namespace Factor{
public class DellKeyBoard:AbstractKeyBoard{
public override void Print(){
Debug.Log("Dell键盘");
}
}
}
namespace Factor{
public class HpMouse:AbstractKeyBoard{
public override void Print(){
Debug.Log("hp键盘");
}
}
}
namespace Factor{
public abstract class FactorBase{
public abstract AbstractMouse CreateMouse();
public abstract AbstractKeyBoard CreateKeyBoard();
}
}
namespace Factor{
public class DellFactor:FactorBase{
public override AbstractMouse CreateMouse(){
return new DellMouse();
}
public override AbstractKeyBoard CreateKeyBoard(){
return new DellKeyBoard();
}
}
}
namespace Factor{
public class HpMouse:FactorBase{
public override AbstractMouse CreateMouse(){
return new HpMouse();
}
public override AbstractKeyBoard CreateKeyBoard(){
return new HpKeyBoard();
}
}
}
--snip--
public class FactorMain:MonoBehaviour{
void Start(){
RunAbstractFactor();
}
--snip--
void RunAbstractFactor(){
DellFactor dellFactor = new DellFactor();
AbstractMouse dellmouse = dellFactor.CreateMouse();
dellMouse.Print();
AbstractKeyboard dellKeyBoard = dellFactor.CreateKeyBoard();
dellKeyBoard.Print();
HpFactor hpFactor = new HpFactor();
AbstractMouse hpmouse = hpFactor.CreateMouse();
hpmouse.Print();
AbstractKeyboard hpKeyBoard = hpFactor.CreateKeyBoard();
hpKeyBoard .Print();
}
}
适配器模式
概念:可以用同一种方式调用不同平台上的同一个功能。
namespace Adaptor{
public class AndroidLine{
public void AndroidCharge(){
Debug.Log("借助Android数据线充电中");
}
}
}
namespace Adaptor{
public class IOSLine{
public void IOSCharge(){
Debug.Log("借助IOS数据线充电中");
}
}
}
namespace Adaptor{
public enum AdaptorType{
None,
Android,
IOS,
}
public interface IAdaptor{
void Charge(AdaptorType adaptorType);
}
public class Adaptor:IAdaptor{
AndroidLine androidLine = new AndroidLine();
IOSLine iosLine = new IOSLine();
public void Charge(AdaptorType adaptorType){
if(adaptorType == AdaptorType.Android)
androidLine.AndroidCharge();
else if(adaptorType == AdaptorType.IOS){
iosLine.IOSCharge();
}
}
}
}
namespace Adaptor{
public class AdaptorMain"MonoBehaviour{
void Start(){
// 用的时候统一调用接口即可
IAdaptor adaptor = new Adaptor();
adaptor.Charge(AdaptorType.Android);
adaptor.Charge(AdaptorType.IOS);
}
}
}
注意:考虑到如果还有许多代码的情况下,这里接口用于拓展原始类不足的功能。
IO操作
C#字符串
参考:https://www.runoob.com/csharp/csharp-string.html
举例:
public class StringTest{
void Start(){
Test1();
}
void Test1(){
string str1 = "XIAOXING";
string str2 = "xiaoxing";
Debug.Log(str1.Length); // 长度
Debug.Log(string.Compare(str1,str2));//相等输出整形0,不等输出1
Debug.Log(string.Concat(str1,str2));//拼接
Debug.Log(string.Format("name:{0} age:{1}","张三",14))//格式化输出
Debug.Log(str1.Contains("I"));//判断是否存在目标字符串
Debug.Log(str1.IndexOf("I"));//字符串第一次出现的索引
string [] array = str1.Split(new char[] {'G'});//字符串切割
}
}
StringBuilder的使用
参考博客:https://blog.csdn.net/sibaison/article/details/72356393
用途:创建新的String的系统开销可能非常安规,如果要修改字符串而不创建新的对象,可以用到这个类。
public class StringBuilderTest{
void Start(){
Test1();
}
void Test1(){
stringBuilder sb = new StringBuilder("Hello World",25);//内容和最大长度
Debug.Log(sb.Length + sb.capacity); //长度+容量
sb = sb.Append("What a beautiful day!"); // 添加内容
Debug.Log(sb.ToString());
}
}
文件读写
参考链接:http://c.biancheng.net/csharp/file-io.html
using UnityEngine;
public class FileStreamTest:MonoBehaviour{
void CreateFile(){
string path = @"E:\WorkSpace\Project\Assets\Resources\student.txt";
FileStream fileStream = new FileStream(path,FileMode.OpenOrCreate,FileAccess.ReadWrite,FileShare.ReadWrite);
string msg = "1710026"
byte[] bytes = Encoding.UTF8.GetBytes(msg);//字符串转换为字节数组
fileStream.Write(bytes,0,bytes.Length);
fileStream.Flush();//刷新缓冲区
fileStream.Close();//关闭流
}
void ReadFile(){
string path = @"E:\WorkSpace\Project\Assets\Resources\student.txt";
if(File.Exists(path)){
FileStream fileStream = new FileStream(path,FileMode.Open,FileAccess.Read);
byte[] bytes = new byte(fileStream.Length);
fileStream.Read(bytes,0,bytes.Length);
string s = Encoding.UTF8.GetString(bytes);
Debug.Log(s)
fileStream.Close();
}
else{
Console.WriteLine("您查看的文件不存在");
}
}
void WriteAndRead{ //另一种方法
// 要写入文件中的数据
string[] str = new string[]{
"C语言中文网",
"http://c.biancheng.net/",
"C# 教程"
};
// 创建 StreamWriter 类的对象
StreamWriter file = new StreamWriter("demo.txt");
// 将数组中的数据写入文件
foreach(string s in str){
file.WriteLine(s);
}
file.Close();
// 读取文件中的内容
string line = "";
StreamReader readfile = new StreamReader("demo.txt");
while((line = readfile.ReadLine()) != null){
Console.WriteLine(line);
}
readfile.Close();
Console.ReadKey();
}
}
用Directory和DirectoryInfo操作文件夹
参考链接:http://c.biancheng.net/csharp/directory.html
一个是静态操作,一个是创建对象后操作
string strDir = @"E:\"
Directory.CreateDirectory(strDir);
Directory.Exists(strDir); //判断文件夹是否存在
Directory.Delete(strDir); //删除文件夹,如果有子文件夹需要加参数true
Directory.Move(strDir,@"D:\");//移动文件夹
DirectoryInfo directoryInfo = new DirectoryInfo(strDir);
directoryInfo.Create(); //创建文件夹
directoryInfo.CreateSubdirectory("code-1"); //创建子文件夹
directoryInfo.Delete(); //删除文件夹,如果有子文件夹需要加参数true
directoryInfo.MoveTo("D:\"); // 移动文件夹
数据结构
数组
含义:数组是用来储存数据的集合,元素类型相同,固定长度,顺序集合。
int[] array1 = new int[3];
int[] array2 = new int[3]{1,2,3};
int[] array3 = {1,2,3,4,5};
array1[0] = 5; //赋值
Debug.Log(array1[0]); //读取
foreach(var v in array2){
Debug.Log(v);
}
动态数组
动态数组会自动调整大小,可以在指定位置添加删除项目,允许在列表中动态分配内存。
ArrayList arraylist1 = new ArrayList();
arraylist1.Add(45); //添加一个数据
int[] array3 = {1,2,3,4,5};
arraylist1.AddRange(array3); //添加一组数据
arraylist1.Clear(); //清空
arraylist1.Contains(12); //判断是否包含特定元素
arraylist1.IndexOf(12); //返回第一次出现的元素索引,没有返回-1
arraylist1.Insert(3,66); //索引+插入元素
arraylist1.Remove(12); // 删除第一次出现的元素
arraylist1.Reverse(); //翻转元素
arraylist1.Sort(); //按顺序排列
列表
和泛型结合使用,作用与功能类似arraylist,无需装箱拆箱,类型转换,提前定义元素类型,比较安全,编译时就能检查错误。
List<int> list1 = new List<int>();
list1.Add(1);
// 和arraylist函数类似
哈希表
哈希表代表了键值对集合,使用键访问集合中的元素。用法比较简单。
Hashtable ht1 = new Hshtable();
ht1.Add("1",99);
ht1.Clear();
if(ht1.ContainsKey("1")){
Debug.Log("包含键为“1”的数据");
}
ht1.Remove("1");
Debug.Log(ht1["1"]); //读取
ht1["1"]=99; //修改
ICollection key = ht1.Keys;
foreach(var k in key){ //遍历
Debug.Log(ht1[k]);
}
字典
字典也存储键值对,但字典也是和泛型一起用的,提前指导好键值的数据类型。
Dictionary<string,string> dict1 = new Dictionary<string,string>();
dict.add("1","100");
if(dict1.ContainsKey("1")){
Debug.Log("键存在");
}
dict1["1"] = 100;
foreach(KeyValuePair<string,string> kvp in dict1){
Debug.Log(kvp.Key + " " + kvp.Value);
}
dict1.Remove("2");
dict1.Clear();
哈希集
包含不重复项的无序集合
HashSet<int> hs1 = new HashSet<int>();
HashSet<int> hs2 = new HashSet<int>();
hs1.Add(1);
hs1.Add(2);
hs1.Add(2); //重复无效
Debug.Log(hs1.count); //计算个数
hs2.Add(2);
hs2.Add(3);
hs1.IntersectWith(hs2); //h1取交集
hs1.UnionWith(hs2); // h1取并集
hs1.ExceptWith(hs2); //h1取差集
hs1.SymmetricExceptWith(hs2); //对称差集,即并集中去掉交集的部分
链表
C#中是有前驱和后驱的双向链表。链表在内存中是离散的,不连续。通过两个指针指向上一个存储位置和上一个存储位置。
链表在删除和插入的时候效率比列表和数组快,但查找的时候只能靠遍历,比较慢。
LinkedList<int> linList = new LinkedList<int>();
LinkedListNode<int> node;
node = linList.AddFirst(1); //第一个节点
linlist.AddAfter(node,2); //添加在某节点后面+具体值
linlist.AddBefore(node,0); //添加在某节点前面+具体值
Debug.Log(linList.Count);
Debug.Log(linList.First.Value); //第一个值
Debug.Log(linList.Last.Value); //最后一个值
Debug.Log(node.Previous.Value); //节点前一个值
Debug.Log(node.Next.Value); //节点后一个值
堆栈
先进后出的对象集合
Stack st1 = new Stack();
st1.Push("a");
st1.Push("b");
st1.Push("c");
Debug.Log(st1.Count);
string v = (string)st1.Pop();
v = st1.Peek(); //拿到栈顶的值,不出栈
foreach(var v in st1){
Debug.Log(v1);
}
// 自己实现,使用链表的形式
class MyStack{
class StackData{
public StackData nextItem;
public object topData;
public StackData(StackData next,object data){
this.nextItem = next;
this.topData = data;
}
StackData top;
public void Push(object data){
top = new StackData(top,data);
}
public object Pop(){
object rs1 = top.topData;
top = top.nextItem;
return rs1;
}
}
}
MyStack ms = new MyStack();
ms.Push("a");
ms.Push("b");
ms.Push("c");
string v = ms.Pop();
队列
先进先出的队列集合
Queue queue1 = new Queue();
Queue<int> queue2 = new Queue<int>(); // 更多使用这种,效率高,不用装箱拆箱
queue2.Enqueue(1); //入队
queue2.Enqueue(2);
int v = queue2.Dequeue();
// 自己实现
class MyQueue{
class QueueData{
public QueueData nextItem;
public object topData;
public QueueData(QueueData last,object data){
last.nextItem = this;
this.topData = data;
}
QueueData top;
QueueData lastData;
public void Enqueue(object data){
if(top == null){
top = new QueneData(data);
}
else{
lastData = new QueueData(lastData,data);
}
}
public object Dequeue(){
object rs1 = top.topData;
top = top.nextItem;
return rs1;
}
}
}
Queue mq1 = new MyQueue();
mq1.Enqueue(1); //入队
mq1.Enqueue(2);
int v = mq1.Dequeue();
int v = mq1.Dequeue();