习题:声明一个Monster类,有一个Attack方法,用一个ArrayList去封装Monster的对象,装10个,遍历monster的list让他们释放攻击方法
创建一个武器类,有一个属性叫做id,每个武器对象的id不一样,创建10把武器,把这10把武器通过id,存储在哈希表中,可以通过id在哈希表中找到对应的武器
手动输入一组数列(可任意长度),并对这个数列进行排序,每次提示用户输入:1、添加一个数字;2、排序并显示数列
书写一个怪物(Monster)类,在怪物类的构造中将其添加到一个静态列表,以怪物类做为基类派生Boss和Gablin的对象产生不用的攻击行为(多态),可以写一个方法,让怪物按攻击力进行排序从小到大。
老师们会在下课时打铃(事件) 学生们想在打铃事件发生的时候做自己的事情;小明想在打铃的时候去买东西吃;小张想在打铃时去打水;小红想在打铃时去打羽毛球
有一个int类型的List,升序排序和降序排序,不能使用List的Sort方法,只能自己写一个排序的方法,通过委托传递方法变量去改变排序的逻辑
数据结构
描述数据之间的关系
删除数据:向结构中删除指定的数据
所以在内存不是连续的空间,而是一个一个的空间,通过头尾地址连接在一起
集合
ArrayList、HashTable、Stack、Queue
如果你是用这些数据结构类的模板,要先引用System.Collections;
动态数组ArrayList
因为Object类型是所有类的父类,又因为里氏转化原则,父类可以装载子类,所以ArrayList可以装载所有数据类型
属性:
方法:
添加.Add(Object value) 把当前这个对象添加到数组中
删除 .Remove(Object value) 查询此元素,并移除第一个匹配的元素项
.RemoveAt(int index) 根据下标号移除该元素
插入 .Insert(int index ,Object value) 把对应对象插入到对应的下标
排序:Sort();
检测该集合是否包含改元素,如果包含返回true,不包含返回false
如果没找到,则返回-1
习题:声明一个Monster类,有一个Attack方法,用一个ArrayList去封装Monster的对象,装10个,遍历monster的list让他们释放攻击方法
internal class Monster
{
public string name;
public Monster(string name)
{
this.name = name;
}
public void Attack()
{
Console.WriteLine("{0}攻击了", name);
}
}
static void Main(string[] args)
{
ArrayList monsterList=new ArrayList();
for(int i=0;i<10;i++)
{
monsterList.Add(new Monster("第"+i+"号哥布林"));
}
for (int i = 0; i < monsterList.Count; i++)
{
if(monsterList[i] is Monster)
{
(monsterList[i] as Monster).Attack();
//ArrayList装载的是Object类型,需要里氏转换原则
}
}
}
哈希表HashTable
它储存的也是object类型的对象,但是它在内存中是散列排布的
在HashTable中一个键只能对应一个值,一个值可以对应多个键,多对一的关系
HashTable table=new HashTable();
属性:
方法:
因为一个值有可能对应多个键,这样就不能把整个键值对删除掉
只要没有键指向这个值,就会自动被释放掉,所以只需要删除键值就可以了
foreach(var key in table.keys)
{
Console.WriteLine(hashtable[key]);
}
创建一个武器类,有一个属性叫做id,每个武器对象的id不一样,创建10把武器,把这10把武器通过id,存储在哈希表中,可以通过id在哈希表中找到对应的武器
static void Main(string[] args)
{
Hashtable table=new Hashtable();
//假设有一把武器,叫霜之哀伤,id为123
//并把霜之哀伤放进我的武器目录里
Weapon a = new Weapon("霜之哀伤");
table.Add("123",a);
table.Add("456",a);
Console.WriteLine(table["456"]);
}
internal class Weapon
{
public string name;
public Weapon(string name)
{
this.name = name;
}
public override string ToString()
{
return name;
}
}
栈Stack
也是System.Collections下的数据结构类,存储的依然是Object 类型的对象
Count:实际拥有的元素个数
栈的释放顺序是先进后出
压栈——Push(Object 对象)把这个对象添加到栈的顶部
弹栈——Pop()把栈顶的元素弹出来,会删除
Peek() 返回栈顶的元素,不删除
在遍历弹栈的时候要注意,pop方法会删除你的对象,导致Count属性发生改变,
所以,应该用一个变量存储一下一开始的Count值,根据这个变量,来弹栈就可以把栈中所有的数据弹出去
for(int i=0;i<10;i++)
{
stack.Push(i);
}
for(int i=0;i<static_Count;i++)
{
Console.WriteLine(stack.Pop());
}
栈在游戏开发中的应用
用来实现”返回/撤销”功能。可以将每一步的操作或者是坐标信息加入到stack中,当玩家按下返回/撤销键时将上一步操作从栈中移除并根据其中的信息在游戏中反向操作
常常被用到在游戏”状态/窗口/场景”管理中。在游戏中,往往会有多个窗口叠加在一起,或者从一个场景进入到子场景。这时,通过在进入“新场景/打开新窗口”时,将这个”场景/窗口”加入到stack中,玩家选择返回时再从栈中弹出并销毁,所有的事件和操作都只对当前的顶端的窗口生效
队列Queue
是System.Collections下的数据结构类,存储Object类型的对象
Queue queue=new Queue();
Count:该结构包含的元素个数
方法:
Peek() 队列中队首的元素返回,但不删除
游戏开发中的应用
回合制游戏中的行动顺序队列(Turn Queue)
回合制和半回合制游戏中常常有速度、行动力的概念来决定场上所有单位的行动顺序,这个时候可以通过队列来安排。当然,很多游戏中会有提升或降低速度的技能和物品,这个时候会需要重新生成队列。管理经营类游戏中的生产队列
很多管理经营类游戏,或者即时战略游戏中都会有生产队列的概念。通过使用队列来提前规划之后的生产顺序可以使玩家操作起来更为方便。一个典型的例子就是文明系列中在城市里的生产列队,提前安排之后需要生成的单位或设施,将后续需要制造的东西依次加入队列,当当前生产任务完成时,从队列中移除并获取下一个需要生成的单位。行动队列
很多及时战略游戏和MOBA类游戏中都有用队列提前安排之后的行动的功能。例如DotA中可以在TP的时候按住Shift将跳刀加到行动队列中实现落地瞬间跳走,沙王施法前摇时将跳到放到队列中实现跳大等操作。剧情对话
当剧情对话会因为玩家的选择产生分支的时候,常常需要用树结构来储存,但归根结底,这可以被当作一种非线性的队列。实际运行的时候,还是可以用Queue来储存和操作正在播放的剧情文字,分支产生并被选择以后再将该分支下的对话加入到队列中。动画播放,多节点移动
游戏动画中,有时候会有沿着一系列节点移动的操作,这个过程可以使用队列来完成,将所有节点按照顺序加入队列,然后用dequeue获取并移除队列顶端的点来实现按照相同顺序移动。消息、事件的传输和分发
一些网游或者多进程的单机需要用接收、处理从网络或其他进程传入的指令和消息,而当本地在处理消息的时候,其他陆续传入的消息将在队列中等待,然后当前一个任务执行完毕后从队列中获取下一个需要被执行的指令或需要处理的消息。
泛型
因为在编程中想先不定义数据类型,只想先写逻辑,可以使用Object类型,这样逻辑就适用于所有类型,但是,在运行中,Object类型的变量会需要转换到对应类型,浪费资源,所以出现泛型,代替Object类型的方案
泛型是一种将逻辑应用到不同数据类型上的机制,可以通过类型代替符来暂时代参数的数据类型,这样只需要在编译的时候,编译器会自动将替代符编译成对应数据类型来处理
泛型方法
手动输入一组数列(可任意长度),并对这个数列进行排序,每次提示用户输入:1、添加一个数字;2、排序并显示数列
static void Main(string[] args)
{
List<int> list = new List<int>();
list.Add(1);
list.Add(4);
list.Add(8);
list.Add(2);
list.Add(3);
list.Add(9);
list.Add(5);
list.Add(6);
list.Add(7);
list.Add(10);
Console.WriteLine("提示:用户输入1,可添加一个数字;如果用户输入2,排序并显示此数列");
int a=int.Parse(Console.ReadLine());
if(a==1)
{
list.Add(a);
}
if(a==2)
{
list.Sort();
for(int i=0;i<list.Count;i++)
{
Console.WriteLine(list[i]);
}
}
}
书写一个怪物(Monster)类,在怪物类的构造中将其添加到一个静态列表,以怪物类做为基类派生Boss和Gablin的对象产生不用的攻击行为(多态),可以写一个方法,让怪物按攻击力进行排序从小到大。
static void Main(string[] args)
{
for(int i = 0; i < 10; i++)
{
new Goblin(“第” + i + “号哥布林”);
}
new Boss(“拉格拉罗斯”);
//Console.WriteLine(MonsterManager.monsterList[1]);
for (int i = 0; i < MonsterManager.monsterList.Count; i++)
{
MonsterManager.monsterList[i].Attack();
}
}
{
public static List<Monster> monsterList = new List<Monster>();
public static Random r=new Random();
}
class Monster
{
public int attack;
public Monster (string name)
{
this.name = name;
MonsterManager.monsterList.Add(this);
}
public virtual void Attack()
{ }
public override string ToString()
{
return String.Format(“{0}/攻击力,{i}”,name,attack);
}
}
class Goblin : Monster
{
public Goblin(string name) : base(name)
//先去执行base指向的public Monster (string name),
{
attack =MonsterManager.r.Next(50,100);
}
public override void Attack()
{
Console.WriteLine(“{0}丢了一块石头,砸人特别疼”,name);
}
}
{
public Boss(string name):base(name)
{
attack=MonsterManager.r.Next(200,500);
}
public override void Attack()
{
Console.WriteLine(“{0}一口炎爆术喷了出来,特别吓人”, name);
}
}
字典
书写一个方法,可以把输入的数字转换成中文数字
把123转换为:壹贰参. Dictionary<char,char>
思路:建立一个0-9的字典,作为key存储,对应value壹贰参,输入参数作为键在字典里查找,再把值保存下来
{
static void Main(string[] args)
{
Console.WriteLine(“请输入一个数字”);
string input=Console.ReadLine();
UpperNum(input);
}
public static void UpperNum(string input)
{
Dictionary<string , string> dic = new Dictionary<string, string>();
dic.Add(“1”, “壹”);
dic.Add(“2”, “贰”);
dic[“3”] = “叁”;
dic[“4”] = “肆”;
dic.Add(“5”, “伍”);
dic.Add(“6”, “陆”);
dic[“7”] = “柒”;
dic[“8”] = “捌”;
dic[“9”] = “镹”;
dic[“0”] = “零”;
string result = “”;
for(int i = 0; i < input.Length; i++)
{
result = result+dic[input[i].ToString()];
}
Console.WriteLine(result);
}
}
委托
是方法的载体(引用),可以承载(一个或多个)方法
委托类型名 委托变量名=new 委托类型(返回类型与参数列表一致方法)
委托的赋值
在装载方法的时候,不用写小括号
委托的调用
委托变量名.Invoke(参数);
列表的查找速度比链表要快
回调
委托的本质
就是方法引用的队列,先进先出,一旦调用会把队列中所有的方法执行完
委托的注册
委托名+=方法名
就可以将多个方法注册进委托变量中
委托的注销
委托名-=方法名
可以将方法从委托列表中移除
老师们会在下课时打铃(事件) 学生们想在打铃事件发生的时候做自己的事情;小明想在打铃的时候去买东西吃;小张想在打铃时去打水;小红想在打铃时去打羽毛球
static void Main(string[] args)
{
Teacher t = new Teacher(“王老师”);
Student xiaoming = new Student(“小明”, “买东西吃”);
Student xiaohua = new Student(“小花”, “打羽毛球”);
t.RegisterCallEvent(xiaoming.DoThing);
t.RegisterCallEvent(xiaohua.DoThing);
t.Call();
}
{
public string name;
public void RegisterCallEvent(CallDelegate del)
{
callDel += del;
}
public void LogoutCallEvent(CallDelegate del)
{
callDel -= del;
}
public Teacher(string name)
{
this.name = name;
}
public void Call()
{
Console.WriteLine(“{0}打铃了”, name);
{
callDel();
}
}
}
{
public string name;
public string thing;
public Student(string name,string thing)
{
this.name = name;
this.thing = thing;
}
public void DoThing()
{
Console.WriteLine(name+thing);
}
}
事件
委托变量如果公开出去,很不安全,外部可以随意调用
所以取消public,封装它,可以自己书写两个方法,供外部注册与注销,委托调用在子方法里调用,这样封装委托变量可以使它更安全,这个叫做事件。
特性:
- 外部不能随意调用,只能注册和注销
- 只能自己去调用自己的委托
C#为了方便封装委托变量,推出一个特性event事件,在委托变量前用event修饰这个变量,这个委托变量就变成了事件,这样的话,这个委托变量就算公开出去也没有关系,因为外部只能对这个变量进行注册和注销,只能内部进行触发。
观察者模式
源——收听者
一系列对象来监听另一个对象的行为,被监听者一旦触发事件/发布消息,则被所有监听者收到,然后执行自己的行为
就是使用委托/事件,让一系列对象把它们的行为来注册到我们的委托中
一群对象在观察另外一个对象的行为,当这个对象的行为达成一定条件,则触发了一群对象的反应,要做到以上功能,要搭配事件使用
把一群对象的反应行为注册到被观察的对象的事件中去
匿名委托与Lambda表达式
有一个int类型的List,升序排序和降序排序,不能使用List的Sort方法,只能自己写一个排序的方法,通过委托传递方法变量去改变排序的逻辑
delegate bool SortDel(int a,int b);
{
static void Main(string[] args)
{
List<int> list = new List<int>();
for(int i = 0; i < 10; i++)
{
list.Add(r.Next(1,1000));
}
//匿名方法Sort(list,delegate(int a,int b) { return a>b;});
Sort(list, (a, b) => a < b);//lambad表达式
for(int i = 0; i < list.Count; i++)
{
Console.WriteLine(list[i]);
}
}
public static void Sort(List<int> list,SortDel del)
{
for(int i=0; i < list.Count; i++)
{
for(int j=0; j < list.Count-1-i; j++)
{
if (del(list[j],list[j+1]))
{
int temp=list[j];
list[j]=list[j+1];
list[j+1]=temp;
}
}
}
}
}
匿名方法
直接用delegate关键字代替方法名,后面跟上参数列表与方法体
Delegate(参数列表){方法体}
Lambda表达式 匿名方法的升级
更加简写
(参数列表)=>{方法体}
当你的方法体只有一条语句的时候,可以不写return,甚至可以没有花括号
参数列表的参数甚至可以不写数据类型
如果说方法体里一旦出现了return,一定要加上花括号
泛型委托
自定义泛型委托
delegate T 委托名<T>(T 参数);
- 不带返回类型的泛型委托——Action<类型1,类型2,……,类型n>参数列表对应的参数类型
- 带返回类型的泛型委托——Func<类型1,类型2,……,类型n>参数列表的末尾类型是作为返回类型使用
Action的演示
static void Main(string[] args)
{
Test(100, ActionEvent);
}
public static void ActionEvent(int a)
{
Console.WriteLine(a);
}
public static void Test(int num,Action<int> del)
{
del(num);
}
Func的演示
static void Main(string[] args)
{
List<int> list = new List<int>();
for(int i=0;i<10;i++)
{
list.Add(r.Next(1,100));
}
Sort(list,delegate(int a,int b) { return a>b;});
for(int i=0;i<list.Count;i++)
{
Console.WriteLine(list[i]);
}
}
public static void Sort(List<int> list,Func<int,int,bool> func)
{
for(int i=0;i<list.Count;i++)
{
for(int j=0;j<list.Count-i-1;j++)
{
if(func(list[j],list[j+1]))
{
int temp=list[j];
list[j]=list[j+1];
list[j+1]=temp;
}
}
}
}
原文地址:https://blog.csdn.net/m0_63330263/article/details/134553651
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_8181.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!