首页 > 编程语言 >C#实现类似Lua的table的数据结构

C#实现类似Lua的table的数据结构

时间:2023-03-05 18:00:26浏览次数:38  
标签:index return C# Lua KeyValuePair new table public datas

设计意义

Lua的table是使用键值对的方式存取,在CSharp中对应的是字典。但是字典会判断键存在与否,而且使用Add和Remove方法来实现存取改,长期来说确实不方便,使代码看上去不是很整洁。但是我们可以自己封装一个数据结构来魔方table,使用CSharp的索引器和字典结合,再添加一些共用属性和方法即可。但最终不能像table那样装下万物。

接口设计

  1. 键作为索引器,无论是否存在此键,都会返回一个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);
                }
            }
        }
  1. 整数作为下标,直接获取整个键值对对象,但不允许修改键
点击查看代码
        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>();
        }
  1. 设计迭代器,用户自主选择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();
        }
  1. 公用接口
判断是否用有此键
        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;
            }
        }
  1. 公共属性
获取所有键
        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()
        {
        }
    }
}

测试用例

测试工具:Unity2018VisualStudio2017

创建对象
        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
                {

                }
            }
        }

查看打印结果

image

使用场景

设计思路来源于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

相关文章

  • PAT 甲级 1009 Product of Polynomials
    Thistime,youaresupposedtofind A×B where A and B aretwopolynomials.InputSpecification:Eachinputfilecontainsonetestcase.Eachcaseoccupi......
  • Ehcache初体验
    前言读张开涛写的《亿级流量网站架构核心技术》里面讲到使用Java缓存:堆内缓存,堆外缓存,磁盘缓存,分布式缓存。介绍了几种缓存工具:GauvaCache,Ehcache和MapDB。其中Gauva......
  • MIT 6.1810 Lab:system calls
    lab网址:https://pdos.csail.mit.edu/6.828/2022/labs/syscall.htmlxv6Book:https://pdos.csail.mit.edu/6.828/2022/xv6/book-riscv-rev3.pdfUsinggdb总体感觉,对xv6的调......
  • 初探富文本之CRDT协同实例
    初探富文本之CRDT协同实例在前边初探富文本之CRDT协同算法一文中我们探讨了为什么需要协同、分布式的最终一致性理论、偏序集与半格的概念、为什么需要有偏序关系、如何通......
  • CentOS下的挂载磁盘和逻辑卷
    挂载分区#查看磁盘情况,找到未挂载的磁盘名fdisk-l#找新挂载的磁盘进行分区2Gfdisk/dev/sdb#根据指引#n新建分区#p创建主分区#1创建第几个分区#输入磁盘阵列......
  • A. Amazing Trick
    A.AmazingTrick思路对于p数组,每个数只有两个禁止的位置不能是自己,并且a[pi]也不是。也就是每个点限制有两个位置不能放,可行的种类有很多,但是模拟起来又较复杂,所以采......
  • GoogleTranslateIpCheck解决谷歌翻译失效
    1、问题:最近谷歌翻译一直失效,要自己频繁更换hosts的ip,很麻烦2、解决:发现了一个好用的工具,它是自动扫描国内可用的谷歌翻译IP,然后自动更换hosts的ip3、使用:到https://git......
  • HTML与CSS手写-1.手写图片瀑布流效果
    1.column多行布局实现瀑布流column 实现瀑布流主要依赖两个属性。column-count 属性,是控制屏幕分为多少列。column-gap 属性,是控制列与列之间的距离。<!DOCTYPEht......
  • HTML与CSS手写-2.使用CSS绘制几何图形(圆形、三角形、扇形、菱形等)
    使用CSS绘制几何图形(圆形、三角形、扇形、菱形等)//圆形<divclass="circle"></div><style>.circle{border-radius:50%;width:80px;height:80px;backg......
  • MySQL Workbench 8.0 点击Server Status面板Could not acquire management access for
    转载自:MySQLWorkbench8.0点击ServerStatus面板Couldnotacquiremanagementaccessforadministration报错问题解决Win10安装MySQLWorkbench8.0后连接MySQL服务......