设计意义
Lua的table是使用键值对的方式存取,在CSharp中对应的是字典。但是字典会判断键存在与否,而且使用Add和Remove方法来实现存取改,长期来说确实不方便,使代码看上去不是很整洁。但是我们可以自己封装一个数据结构来魔方table,使用CSharp的索引器和字典结合,再添加一些共用属性和方法即可。但最终不能像table那样装下万物。
接口设计
- 键作为索引器,无论是否存在此键,都会返回一个System.Object的对象
点击查看代码
public Object this[string key]
{
get
{
Object result = null;
datas.TryGetValue(key, out result);
return result;
}
set
{
if (datas.ContainsKey(key))
{
datas[key] = value;
}
else
{
Add(key, value);
}
}
}
- 整数作为下标,直接获取整个键值对对象,但不允许修改键
点击查看代码
public KeyValuePair<string, Object> this[int index]
{
get => ElementAt(index);
}
private KeyValuePair<string, Object> ElementAt(int index)
{
if (index < 0)
{
Debug.LogWarning("index must be greater than zero!!!");
return new KeyValuePair<string, Object>();
}
if (index >= Count)
{
Debug.LogWarning("index out of range, please check datas.count");
return new KeyValuePair<string, Object>();
}
int _index = 0;
using (var e = datas.GetEnumerator())
{
while (e.MoveNext())
{
if (_index == index)
{
return e.Current;
}
++_index;
}
}
Debug.LogWarning("index out of range, please check datas.count");
return new KeyValuePair<string, Object>();
}
- 设计迭代器,用户自主选择for或者foreach或enumerator的迭代方式
新建迭代类
public class GameDataEnumerator: IEnumerator<KeyValuePair<string, Object>>, System.IDisposable
{
private Dictionary<string, Object> dockers;
private int enumeratorIndex;
public KeyValuePair<string, object> Current => ElementAt(enumeratorIndex);
object IEnumerator.Current => throw new NotImplementedException();
private GameDataEnumerator()
{
}
public GameDataEnumerator(Dictionary<string, Object> _dockers)
{
enumeratorIndex = -1;
this.dockers = _dockers;
}
private KeyValuePair<string, Object> ElementAt(int index)
{
if (index < 0)
{
Debug.LogError("index must be greater than zero!!!");
return new KeyValuePair<string, Object>();
}
if (index >= dockers.Count)
{
Debug.LogError("index out of range");
return new KeyValuePair<string, Object>();
}
int _tempIndex = 0;
using (var e = dockers.GetEnumerator())
{
while (e.MoveNext())
{
if (_tempIndex == index)
{
return e.Current;
}
++_tempIndex;
}
}
return new KeyValuePair<string, Object>();
}
public bool MoveNext()
{
++enumeratorIndex;
return enumeratorIndex < dockers.Count;
}
public void Reset()
{
enumeratorIndex = -1;
}
public void Dispose()
{
}
}
获取迭代器
public GameDataEnumerator GetEnumerator()
{
return new GameDataEnumerator(datas);
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
- 公用接口
判断是否用有此键
public bool HaveKey(string key)
{
return datas.ContainsKey(key);
}
判断是否拥有此值
public bool HaveValue(Object value)
{
return datas.ContainsValue(value);
}
重写equal方法
public override bool Equals(object obj)
{
try
{
GameData _compareData = (GameData)obj;
bool isCountEqual = _compareData.Count == this.Count;
bool isKeysEqual = _compareData.Keys.Equals(this.Keys);
bool isValuesEqual = _compareData.Values.Equals(this.Values);
return isCountEqual && isKeysEqual && isValuesEqual;
}
catch
{
return false;
}
}
- 公共属性
获取所有键
public List<string> Keys { get => GetKeys(); }
private List<string> GetKeys()
{
List<string> keys = new List<string>(datas.Count);
using (var e = datas.GetEnumerator())
{
while (e.MoveNext())
{
keys.Add(e.Current.Key);
}
}
return keys;
}
获取所有值
public List<Object> Values { get => GetValues(); }
private List<Object> GetValues()
{
List<Object> values = new List<Object>(datas.Count);
using (var e = datas.GetEnumerator())
{
while (e.MoveNext())
{
values.Add(e.Current.Key);
}
}
return values;
}
获取json字符串
public String Json { get => this.ToString(); }
public override string ToString()
{
return string.Empty;//可以使用json相关的转换工具或者自定义json,转为字符串
}
展示代码
点击查看代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using Object = System.Object;
namespace JunFramework
{
public class GameData :IEnumerable, IDisposable
{
private Dictionary<string, Object> datas;
public int Count { get => datas.Count; }
public List<string> Keys { get => GetKeys(); }
public List<Object> Values { get => GetValues(); }
public String Json { get => this.ToString(); }
public GameData()
{
datas = new Dictionary<string, Object>();
}
public Object this[string key]
{
get
{
Object result = null;
datas.TryGetValue(key, out result);
return result;
}
set
{
if (datas.ContainsKey(key))
{
datas[key] = value;
}
else
{
Add(key, value);
}
}
}
public KeyValuePair<string, Object> this[int index]
{
get => ElementAt(index);
}
public void Add(string key, Object value)
{
datas.Add(key, value);
}
private KeyValuePair<string, Object> ElementAt(int index)
{
if (index < 0)
{
Debug.LogWarning("index must be greater than zero!!!");
return new KeyValuePair<string, Object>();
}
if (index >= Count)
{
Debug.LogWarning("index out of range, please check datas.count");
return new KeyValuePair<string, Object>();
}
int _index = 0;
using (var e = datas.GetEnumerator())
{
while (e.MoveNext())
{
if (_index == index)
{
return e.Current;
}
++_index;
}
}
Debug.LogWarning("index out of range, please check datas.count");
return new KeyValuePair<string, Object>();
}
public bool HaveKey(string key)
{
return datas.ContainsKey(key);
}
public bool HaveValue(Object value)
{
return datas.ContainsValue(value);
}
public void Clear()
{
datas.Clear();
}
public void Dispose()
{
Clear();
datas = null;
}
public override string ToString()
{
return string.Empty;//可以使用json相关的转换工具或者自定义json,转为字符串
}
public override bool Equals(object obj)
{
try
{
GameData _compareData = (GameData)obj;
bool isCountEqual = _compareData.Count == this.Count;
bool isKeysEqual = _compareData.Keys.Equals(this.Keys);
bool isValuesEqual = _compareData.Values.Equals(this.Values);
return isCountEqual && isKeysEqual && isValuesEqual;
}
catch
{
return false;
}
}
private List<string> GetKeys()
{
List<string> keys = new List<string>(datas.Count);
using (var e = datas.GetEnumerator())
{
while (e.MoveNext())
{
keys.Add(e.Current.Key);
}
}
return keys;
}
private List<Object> GetValues()
{
List<Object> values = new List<Object>(datas.Count);
using (var e = datas.GetEnumerator())
{
while (e.MoveNext())
{
values.Add(e.Current.Key);
}
}
return values;
}
public GameDataEnumerator GetEnumerator()
{
return new GameDataEnumerator(datas);
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
public class GameDataEnumerator: IEnumerator<KeyValuePair<string, Object>>, System.IDisposable
{
private Dictionary<string, Object> dockers;
private int enumeratorIndex;
public KeyValuePair<string, object> Current => ElementAt(enumeratorIndex);
object IEnumerator.Current => throw new NotImplementedException();
private GameDataEnumerator()
{
}
public GameDataEnumerator(Dictionary<string, Object> _dockers)
{
enumeratorIndex = -1;
this.dockers = _dockers;
}
private KeyValuePair<string, Object> ElementAt(int index)
{
if (index >= dockers.Count)
{
Debug.LogError("index out of range");
return new KeyValuePair<string, Object>();
}
int _tempIndex = 0;
using (var e = dockers.GetEnumerator())
{
while (e.MoveNext())
{
if (_tempIndex == index)
{
return e.Current;
}
++_tempIndex;
}
}
return new KeyValuePair<string, Object>();
}
public bool MoveNext()
{
++enumeratorIndex;
return enumeratorIndex < dockers.Count;
}
public void Reset()
{
enumeratorIndex = -1;
}
public void Dispose()
{
}
}
}
测试用例
测试工具:Unity2018和VisualStudio2017
创建对象
GameData data = new GameData()
{
{"id", 1},
{"name", "junjiang"},
{"identity", "student"},
{"doAction", new System.Action(DoAction)}
};
data["id"] = 2;
修改值
data["id"] = 2;
data["whatever"] = 0.77f;
查看结果
Debug.Log(data["id"]);
Debug.Log(data["name"]);
Debug.Log(data["identity"]);
Debug.Log(data[0].Key);
Debug.Log(data[0].Value.ToString());
Debug.Log(data["whatever"]);
for循环
for (int i = 0; i < data.Count; i++)
{
try
{
System.Action act = (System.Action)data[i].Value;
act?.Invoke();
}
catch
{
}
}
foreach循环
foreach (var item in data)
{
try
{
System.Action act = (System.Action)item.Value;
act?.Invoke();
}
catch
{
}
}
enumerator循环
using (var e = data.GetEnumerator())
{
while (e.MoveNext())
{
try
{
System.Action act = (System.Action)e.Current.Value;
act?.Invoke();
}
catch
{
}
}
}
查看打印结果
使用场景
设计思路来源于LiteJson的JsonData,设计此最初目的是满足我的游戏框架,各个对象之间传递数据。添加Json属性是为了方便我保存玩家数据,当然也可以设计成XML属性或者Lua属性皆可。当然此数据结构暂时只跑过部分测试案例,我将在开发我的JunFramework框架中不断检验和完善我的GameData。欢迎大家指正和建议
标签:index,return,C#,Lua,KeyValuePair,new,table,public,datas From: https://www.cnblogs.com/JunJiang-Blog/p/17180966.html