利用容器建立一个Pokemon管理器
精灵Pokemon至少包含以下几种属性:
ID (ID唯一,像身份证号一样,用于统一管理)
名字
等级
攻击力
建立一个Pokemon管理器(PokemonManager),实现以下功能:
1、添加精灵(注:ID在添加到管理器中时,才能确定)
2、删除精灵
3、快速按照ID查找指定精灵
4、快速按照名字查找到指定精灵。(可能有多个重名的,用List返回结果)
5、按照等级查找指定精灵。(无论查找到0个或多个,都用List返回结果)
(等级不需要建立字典索引)
注:快速查找,需要提前建立字典索引,以避免循环遍历。
6、思考题:给指定ID的精灵改名字
using System;
using System.Collections.Generic;
namespace test
{
public class Pokemon
{
public int ID;
public string name;
public int grade;
public int attack;
public Pokemon(int ID, string name,int grade ,int attack)
{
this.ID = ID;
this.name = name;
this.grade = grade;
this.attack = attack;
}
public override string ToString()
{
return $"{
{
{ID}-{name}-{grade}-{attack}}}";
}
}
public class PokemonManager
{
Dictionary<int,Pokemon> dict = new Dictionary<int,Pokemon>();
int counter = 1;
//添加精灵
public Pokemon AddPokemon(Pokemon poke)
{
poke.ID = counter;
counter++;
dict.Add(poke.ID, poke);
return poke;
}
//删除精灵
public bool RemovePoke(int id)
{
if (!dict.ContainsKey(id))
{
Console.WriteLine("未找到精灵" + id);
return false;
}
dict.Remove(id);
return true;
}
//查找精灵
public Pokemon FindPokebyID(int id)
{
if (!dict.ContainsKey(id))
{
Console.WriteLine("未找到精灵" + id);;
}
return dict[id];
}
//根据名字查精灵
public List<Pokemon> FindPokebyName(string na)
{
List<Pokemon> plist = new List<Pokemon>();
foreach (Pokemon va in dict.Values)
{
if (va.name == na)
{
plist.Add(va);
}
}
if(plist.Count == 0)
{
Console.WriteLine("未找到精灵" + na);
}
return plist;
}
//根据等级查精灵
public List<Pokemon> FindPokebyGrade(int gra)
{
List<Pokemon> plist = new List<Pokemon>();
foreach (var va in dict.Values)
{
if (va.grade == gra)
{
plist.Add(va);
}
}
if (plist.Count == 0)
{
Console.WriteLine("未找到" + gra+"级的精灵" );
}
return plist;
}
//给指定ID的精灵改名字
public void Changename(int ID, string na)
{
foreach (Pokemon po in dict.Values)
{
if (po.ID == ID)
{
po.name = na;
}
}
return;
}
public void PrintAll()
{
Console.WriteLine("==================");
Console.WriteLine("所有精灵");
foreach (var pair in dict)
{
Console.WriteLine(pair.Key);
Console.WriteLine(pair.Value);
}
Console.WriteLine("==================");
}
}
class Program
{
static PokemonManager pm;
static void Main(string[] args)
{
pm = new PokemonManager();
Pokemon p1 = new Pokemon(001, "aaa", 1, 1);
Pokemon p2 = new Pokemon(002, "qqq", 1, 2);
Pokemon p3 = new Pokemon(003, "www", 3, 3);
Pokemon p4 = new Pokemon(004, "eee", 3, 3);
Pokemon p5 = new Pokemon(005, "rrr", 6, 6);
Pokemon p6 = new Pokemon(006, "rrr", 12, 36);
Pokemon p7 = new Pokemon(006, "rrr", 18, 72);
pm.AddPokemon(p1);
pm.AddPokemon(p2);
pm.AddPokemon(p3);
pm.AddPokemon(p4);
pm.AddPokemon(p5);
pm.AddPokemon(p6);
pm.AddPokemon(p7);
pm.PrintAll();
Console.WriteLine("请输入想要删除的精灵编号");
Console.WriteLine(pm.RemovePoke(int.Parse(Console.ReadLine())));
pm.PrintAll();
Console.WriteLine("请输入想要查找的精灵编号");
Console.WriteLine(pm.FindPokebyID(int.Parse(Console.ReadLine())));
Console.WriteLine("请输入想要查找的精灵名字");
List<Pokemon> fbn1 = pm.FindPokebyName(Console.ReadLine());
if (fbn1 != null)
{
foreach (var item in fbn1)
{
Console.WriteLine(item);
}
}
Console.WriteLine("请输入想要查找的精灵等级");
List<Pokemon> fbg1 = pm.FindPokebyGrade(int.Parse(Console.ReadLine()));
if (fbg1 != null)
{
foreach (var item in fbg1)
{
Console.WriteLine(item);
}
}
Console.WriteLine("请输入想要改名的精灵的ID");
int gid = int.Parse(Console.ReadLine());
Console.WriteLine("请输入改名精灵的目标名字");
string gstr = Console.ReadLine();
pm.Changename(gid, gstr);
pm.PrintAll();
}
}
}
Console:
==================
所有精灵
1
{1-aaa-1-1}
2
{2-qqq-1-2}
3
{3-www-3-3}
4
{4-eee-3-3}
5
{5-rrr-6-6}
6
{6-rrr-12-36}
7
{7-rrr-18-72}
==================
请输入想要删除的精灵编号
2
True
==================
所有精灵
1
{1-aaa-1-1}
3
{3-www-3-3}
4
{4-eee-3-3}
5
{5-rrr-6-6}
6
{6-rrr-12-36}
7
{7-rrr-18-72}
==================
请输入想要查找的精灵编号
4
{4-eee-3-3}
请输入想要查找的精灵名字
rrr
{5-rrr-6-6}
{6-rrr-12-36}
{7-rrr-18-72}
请输入想要查找的精灵等级
3
{3-www-3-3}
{4-eee-3-3}
请输入想要改名的精灵的ID
3
请输入改名精灵的目标名字
jkl
==================
所有精灵
1
{1-aaa-1-1}
3
{3-jkl-3-3}
4
{4-eee-3-3}
5
{5-rrr-6-6}
6
{6-rrr-12-36}
7
{7-rrr-18-72}
==================
E:\Csharp\2023.01.18\ConsoleApp1\ConsoleApp1\bin\Debug\netcoreapp3.1\ConsoleApp1.exe (进程 20364)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
容器与文件操作
static void WriteFile()
{
FileStream file = new FileStream("a.txt", FileMode.Create);
string s = "kfosiwdef2432";
byte[] bytes = Encoding.UTF8.GetBytes(s);
file.Write(bytes, 0, bytes.Length);
file.Close();
}
static void ReadFile()
{
FileStream file = new FileStream("a.txt", FileMode.Open);
byte[] bytes = new byte[10240];
int len = file.Read(bytes,0,10240);
Console.WriteLine(bytes);
string s = Encoding.UTF8.GetString(bytes,0,len);
Console.WriteLine("s:" + s);
}
static void WriteFile()
{
FileStream file = null;
try
{
file = new FileStream("a.txt", FileMode.Create);
string s = "kfosiwdef2432";
//字符串s转byte[]
byte[] bytes = Encoding.UTF8.GetBytes(s);
//写入byte[]到文件
file.Write(bytes, 0, bytes.Length);
}
//catch(UnauthorizedAccessException e)
//{
// Console.WriteLine(e.Message);
//}
//catch (DirectoryNotFoundException e)
//{
// Console.WriteLine(e.Message);
//}
catch(Exception e)
{
Console.WriteLine("基类异常" + e.Message);
}
finally
{
//关闭文件
if(file != null)
{
file.Close();
file = null;
}
}
}
static void ReadFile()
{
using (FileStream file = new FileStream("a.txt", FileMode.Open))
{
byte[] bytes = new byte[10240];
int len = file.Read(bytes, 0, 10240);
Console.WriteLine(bytes);
string s = Encoding.UTF8.GetString(bytes, 0, len);
Console.WriteLine("s:" + s);
}
//using 会自动释放file变量
}
static void WriteFileBin()
{
using(FileStream file = new FileStream("b", FileMode.Create))
{
//创建二进制写入器,绑定在file上面
BinaryWriter writer = new BinaryWriter(file);
//借助二进制写入器写入
writer.Write(123);
writer.Write("你好");
writer.Write(false);
writer.Write(3.14f);
}
}
static void ReadFileBin()
{
using (FileStream file = new FileStream("b", FileMode.Open))
{
//创建二进制读取器
BinaryReader reader = new BinaryReader(file);
int n = reader.ReadInt32();
string s = reader.ReadString();
bool b = reader.ReadBoolean();
float f = reader.ReadSingle();
Console.WriteLine($"{n}{s}{b}{f}");
}
}
为PokemonManager加入写文件、读取文件两个成员函数
要点是设计存储的格式,建议使用二进制序列化方式。
1、先用BinaryReader和BinaryWriter实现
2、如果小精灵有一个List<int>或List<string>字段,应该如何存盘?
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace test
{
public class Pokemon
{
public int ID;
public string name;
public int grade;
public int attack;
public List<int> buff;
public List<string> equipment;
public Pokemon(int ID, string name, int grade, int attack,List<int> buff,List<string>equipment)
{
this.ID = ID;
this.name = name;
this.grade = grade;
this.attack = attack;
this.buff = buff;
this.equipment = equipment;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append($"{
{
{ID}-{name}-{grade}-{attack}}}");
//-{buff}-{equipment}
if (buff != null)
{
sb.Append("buff:[");
foreach (var b in buff)
{
sb.Append(b+",");
}
sb.Remove(sb.Length - 1, 1);
sb.Append("]");
}
if (equipment != null)
{
sb.Append("equipment:");
foreach(var e in equipment)
{
sb.Append(e + ",");
}
sb.Remove(sb.Length - 1, 1);
}
return sb.ToString();
}
}
public class PokemonManager
{
Dictionary<int, Pokemon> dict = new Dictionary<int, Pokemon>();
int counter = 1;
//添加精灵
public Pokemon AddPokemon(Pokemon poke)
{
poke.ID = counter;
counter++;
dict.Add(poke.ID, poke);
return poke;
}
//删除精灵
public bool RemovePoke(int id)
{
if (!dict.ContainsKey(id))
{
Console.WriteLine("未找到精灵" + id);
return false;
}
dict.Remove(id);
return true;
}
//查找精灵
public Pokemon FindPokebyID(int id)
{
if (!dict.ContainsKey(id))
{
Console.WriteLine("未找到精灵" + id);;
}
return dict[id];
}
//根据名字查精灵
public List<Pokemon> FindPokebyName(string na)
{
List<Pokemon> plist = new List<Pokemon>();
foreach (Pokemon va in dict.Values)
{
if (va.name == na)
{
plist.Add(va);
}
}
if(plist.Count == 0)
{
Console.WriteLine("未找到精灵" + na);
}
return plist;
}
//根据等级查精灵
public List<Pokemon> FindPokebyGrade(int gra)
{
List<Pokemon> plist = new List<Pokemon>();
foreach (var va in dict.Values)
{
if (va.grade == gra)
{
plist.Add(va);
}
}
if (plist.Count == 0)
{
Console.WriteLine("未找到" + gra+"级的精灵" );
}
return plist;
}
//给指定ID的精灵改名字
public void Changename(int ID, string na)
{
foreach (Pokemon po in dict.Values)
{
if (po.ID == ID)
{
po.name = na;
}
}
return;
}
public void PrintAll()
{
Console.WriteLine("==================");
Console.WriteLine("所有精灵");
foreach (var pair in dict)
{
Console.WriteLine(pair.Key);
Console.WriteLine(pair.Value);
}
Console.WriteLine("==================");
}
public void Serialize()
{
//把字典内容转成字符串
StringBuilder sb = new StringBuilder();
foreach(var pair in dict)
{
Pokemon po = pair.Value;
sb.Append($"{po.ID},{po.name},{po.grade},{po.attack}");
sb.Append("\n");
}
string s = sb.ToString();
WriteFile("a.txt", s);
Console.WriteLine("PokeMon已保存为a.txt");
}
public void Deserialize(string ss)
{
string s = ReadFile(ss);
//s 转换回对象
string[] lines = s.Split('\n');
for(int i = 0; i < lines.Length; i++)
{
string line = lines[i];
string[] pars = line.Split(',');
//还原对象
Pokemon po = new Pokemon(0,"0",0,0,null,null);
po.ID = int.Parse(pars[0]);
po.name = pars[1];
po.grade = int.Parse(pars[2]);
po.attack = int.Parse(pars[3]);
//添加到当前这个道具管理器里
AddPokemon(po);
}
}
public void WriteFile(string path,string s)
{
//打开文件
using(FileStream file = new FileStream("a.txt", FileMode.Create))
{
//字符串s转byte[]
byte[] bytes = Encoding.UTF8.GetBytes(s);
//写入byte[]到文件
file.Write(bytes, 0, bytes.Length);
}
}
public static string ReadFile(string path)
{
string s = "";
using (FileStream file = new FileStream(path, FileMode.Open))
{
byte[] bytes = new byte[10240];
//file.Read(字节数组,开始下标,最多读取的字节数)
//len是实际读取的字节数
int len = file.Read(bytes, 0, 10240);
//Console.WriteLine(bytes);
s = Encoding.UTF8.GetString(bytes, 0, len);
}
return s;
}
public void SerializeBin()
{
using(FileStream file = new FileStream("bb", FileMode.Create))
{
//创建二进制写入器,绑定于file上面
BinaryWriter writer = new BinaryWriter(file);
//写入道具数量
writer.Write(dict.Count);
foreach(var pair in dict)
{
Pokemon po = pair.Value;
writer.Write(po.ID);
writer.Write(po.name);
writer.Write(po.grade);
writer.Write(po.attack);
//写入list
if(po.buff == null)
{
writer.Write(0);
}
else
{
writer.Write(po.buff.Count);
for (int i = 0; i < po.buff.Count; i++)
{
writer.Write(po.buff[i]);
}
}
if(po.equipment == null)
{
writer.Write(0);
}
else
{
writer.Write(po.equipment.Count);
for(int i = 0; i < po.equipment.Count; i++)
{
writer.Write(po.equipment[i]);
}
}
}
}
Console.WriteLine("已存盘");
}
public void DeserializeBin(string str)
{
using(FileStream file = new FileStream(str, FileMode.Open))
{
//创建二进制读取器
BinaryReader reader = new BinaryReader(file);
//循环读取
//while (file.Length!=file.Position)
int num = reader.ReadInt32();
for (int i = 0; i < num; i++) ;
{
Pokemon po = new Pokemon(0, "", 0, 0,null,null);
po.ID = reader.ReadInt32();
po.name = reader.ReadString();
po.grade = reader.ReadInt32();
po.attack = reader.ReadInt32();
//读取list
int len1 = reader.ReadInt32();
if (len1 > 0)
{
po.buff = new List<int>();
for (int j = 0; j < len1; j = j + 1)
{
po.buff.Add(4);
po.buff.Add(reader.ReadInt32());
}
}
int len2 = reader.ReadInt32();
if (len2 > 0)
{
po.equipment = new List<string>();
for(int j = 0; j < len2; j++)
{
po.equipment.Add(reader.ReadString());
}
}
AddPokemon(po);
}
}
}
}
class Program
{
static PokemonManager pm;
static void Main(string[] args)
{
pm = new PokemonManager();
Pokemon p1 = new Pokemon(001, "aaa", 1, 1, null, null);
Pokemon p2 = new Pokemon(002, "qqq", 1, 2, null, null);
Pokemon p3 = new Pokemon(003, "www", 3, 3, null, null);
Pokemon p4 = new Pokemon(004, "eee", 3, 3, null, null);
Pokemon p5 = new Pokemon(005, "rrr", 6, 6, null, null);
Pokemon p6 = new Pokemon(006, "rrr", 12, 36, null, null);
Pokemon p7 = new Pokemon(006, "rrr", 18, 72, null, null);
p4.buff = new List<int> { 1, 6, 8 };
p5.buff = new List<int> { 7, 7 };
p5.equipment = new List<string> { "卢登", "法穿鞋","杀人书" };
p6.equipment = new List<string> { "多兰剑", "无尽之刃" };
pm.AddPokemon(p1);
pm.AddPokemon(p2);
pm.AddPokemon(p3);
pm.AddPokemon(p4);
pm.AddPokemon(p5);
pm.AddPokemon(p6);
pm.AddPokemon(p7);
pm.PrintAll();
Console.WriteLine("请输入想要删除的精灵编号");
Console.WriteLine(pm.RemovePoke(int.Parse(Console.ReadLine())));
pm.PrintAll();
Console.WriteLine("请输入想要查找的精灵编号");
Console.WriteLine(pm.FindPokebyID(int.Parse(Console.ReadLine())));
Console.WriteLine("请输入想要查找的精灵名字");
List<Pokemon> fbn1 = pm.FindPokebyName(Console.ReadLine());
if (fbn1 != null)
{
foreach (var item in fbn1)
{
Console.WriteLine(item);
}
}
Console.WriteLine("请输入想要查找的精灵等级");
List<Pokemon> fbg1 = pm.FindPokebyGrade(int.Parse(Console.ReadLine()));
if (fbg1 != null)
{
foreach (var item in fbg1)
{
Console.WriteLine(item);
}
}
Console.WriteLine("请输入想要改名的精灵的ID");
int gid = int.Parse(Console.ReadLine());
Console.WriteLine("请输入改名精灵的目标名字");
string gstr = Console.ReadLine();
pm.Changename(gid, gstr);
pm.PrintAll();
Console.WriteLine("请输入 1存盘 2读取 3二进制存盘 4二进制读取");
string input1 = Console.ReadLine();
if (input1 == "1")
{
pm.Serialize();
}
else if (input1 == "2")
{
Console.WriteLine("请输入文件名");
pm.Deserialize(Console.ReadLine());
}
else if (input1 == "3")
{
pm.SerializeBin();
}
else if (input1 == "4")
{
Console.WriteLine("请输入文件名");
pm.Deserialize(Console.ReadLine());
}
pm.PrintAll();
Console.WriteLine("请输入 1存盘 2读取 3二进制存盘 4二进制读取");
string input2 = Console.ReadLine();
if (input2 == "1")
{
pm.Serialize();
}
else if (input2 == "2")
{
Console.WriteLine("请输入文件名");
pm.Deserialize(Console.ReadLine());
}
else if(input2 == "3")
{
pm.SerializeBin();
}
else if(input2 == "4")
{
Console.WriteLine("请输入文件名");
pm.DeserializeBin(Console.ReadLine());
}
pm.PrintAll();
Console.ReadLine();
}
}
}
Console:
----
==================
所有精灵
1
{1-aaa-1-1}
2
{2-qqq-1-2}
3
{3-www-3-3}
4
{4-eee-3-3}buff:[1,6,8]
5
{5-rrr-6-6}buff:[7,7]equipment:卢登,法穿鞋,杀人书
6
{6-rrr-12-36}equipment:多兰剑,无尽之刃
7
{7-rrr-18-72}
==================
请输入想要删除的精灵编号
2
True
==================
所有精灵
1
{1-aaa-1-1}
3
{3-www-3-3}
4
{4-eee-3-3}buff:[1,6,8]
5
{5-rrr-6-6}buff:[7,7]equipment:卢登,法穿鞋,杀人书
6
{6-rrr-12-36}equipment:多兰剑,无尽之刃
7
{7-rrr-18-72}
==================
请输入想要查找的精灵编号
3
{3-www-3-3}
请输入想要查找的精灵名字
rrr
{5-rrr-6-6}buff:[7,7]equipment:卢登,法穿鞋,杀人书
{6-rrr-12-36}equipment:多兰剑,无尽之刃
{7-rrr-18-72}
请输入想要查找的精灵等级
5
未找到5级的精灵
请输入想要改名的精灵的ID
6
请输入改名精灵的目标名字
jkl
==================
所有精灵
1
{1-aaa-1-1}
3
{3-www-3-3}
4
{4-eee-3-3}buff:[1,6,8]
5
{5-rrr-6-6}buff:[7,7]equipment:卢登,法穿鞋,杀人书
6
{6-jkl-12-36}equipment:多兰剑,无尽之刃
7
{7-rrr-18-72}
==================
请输入 1存盘 2读取 3二进制存盘 4二进制读取
3
已存盘
==================
所有精灵
1
{1-aaa-1-1}
3
{3-www-3-3}
4
{4-eee-3-3}buff:[1,6,8]
5
{5-rrr-6-6}buff:[7,7]equipment:卢登,法穿鞋,杀人书
6
{6-jkl-12-36}equipment:多兰剑,无尽之刃
7
{7-rrr-18-72}
==================
请输入 1存盘 2读取 3二进制存盘 4二进制读取
4
请输入文件名
bb
==================
所有精灵
1
{1-aaa-1-1}
8
{8-aaa-1-1}
3
{3-www-3-3}
4
{4-eee-3-3}buff:[1,6,8]
5
{5-rrr-6-6}buff:[7,7]equipment:卢登,法穿鞋,杀人书
6
{6-jkl-12-36}equipment:多兰剑,无尽之刃
7
{7-rrr-18-72}
==================
文本/二进制序列化、文本/二进制反序列化
通过查找资料,找到更多序列化的手段和写法。
1、这些序列化方法属于文本序列化,还是二进制序列化?
2、它们常用在哪些地方?
3、尝试LitJson的基本使用方法。
(12条消息) Unity/C# Xml序列化 与 二进制序列化_unity二进制序列化_ssuper41的博客-CSDN博客
(12条消息) 【C#进阶七】C#中的序列化与反序列化上(二进制序列化、XML序列化及JSON序列化)_QHCV的博客-CSDN博客
文本序列化将要序列化的内容使用某种编码比如(gbk或utf-8)进行处理,二进制编码简单来说是把内存中的数据按其在内存中的存储形式原样取出。但不管是文本文件还是二进制文件,其实质都是二进制的形式。
1、二进制序列化,文本序列化
二进制序列化:二进制序列化、SOAP序列化、ProtoBuf序列化
二进制序列化 【将对象的内存映射抽取出来形成字符串,还原时只有一个重新分配内存的过程。还原后依然还是你原来的对象】
SOAP序列化【SOAP协议是一个在异构的应用程序之间进行信息交互的理想的选择;SOAP序列化的主要优势在于可移植性。SoapFormatter把对象序列化成SOAP消息或解析SOAP消息并重构被序列化的对象。SOAP序列化不能序列化泛型类型】
ProtoBuf序列化【Protobuf是google提供的一个开源序列化框架,类似于XML,JSON这样的数据表示语言,其最大的特点是基于二进制,因此比传统的XML表示高效短小得多。除了比Json、XML有速度上的优势和使用上的方便外,protocolbuf还可以做到向前兼容和向后兼容;可以自动生成 java 代码支持用.proto文件描述 java 类,并通过 protoc.exe 编译器自动生成代码】
文本序列化:XML序列化、Json序列化
Xml序列化【XML 是各种应用程序之间进行数据传输的工具;在发送端时java ,接收端可以时任何js,python,ruby不受环境限制】
JSON序列化 【JSON是传输数据的一种格式,是将对象的属性以键值对的形式组织成字符串(一个编码过程),体积会增大很多,而且解码后也不能直接还原回原来的对象;比起xml,数据更精简,还能和js配对使用】
2、常用地方
二进制序列化:用于不同的应用程序之间共享对象时;用于将对象序列化到流、磁盘、内存和网络时;远程处理时;“按值”在计算机或应用程序域之间传递对象时。
SOAP序列化:用于提供或使用数据而不限制使用该数据的应用程序时;通过 Web 共享数据时。
ProtoBuf序列化:用于网络数据传输及存储
XML序列化:用于提供或使用数据而不限制使用该数据的应用程序时;通过 Web 共享数据时。
JSON 序列化:用于通过 Web 共享数据时。
3、LitJson的基本使用方法
JsonMapper.ToObject():把json字符串转成对象
JsonMapper.ToJson():把对象转成json字符串