代码之家  ›  专栏  ›  技术社区  ›  Ryan Leach

C#类型安全字典,其中值取决于键?i字典<键<值>,值>?

  •  0
  • Ryan Leach  · 技术社区  · 6 年前

    我不知道这个数据结构的正确名称(它是同构映射吗?),但基本上我是想得到这样的东西。

    SmartDict dict = new SmartDict();
    Key<string> NameKey = new Key<string>("nameID"); // Should this be a generated GUID for serialization that must be registered?
    Key<int> HealthKey = new Key<int>("healthID"); //Should this be a generated GUID for serialization that must be registered?
    dict[NameKey] = "Ryan";
    dict[HealthKey] = 20;
    String name = dict[NameKey]; //name is now Ryan
    int health = dict[HealthKey];
    

    假设这是在数据类的某个实例的基类上定义的,而该实例不容易为每次使用进行自定义。 通过将SmartDict附加到基类,然后可以向该类添加其他数据(并在将来将其序列化为blob),并让it数据驱动需要附加的类型和其他数据(只要它们也可以序列化)。

    class BaseEntity {
        public SmartDict dict = new SmartDict();
        Key<string> NameKey = new Key<string>("name");
    
        public void Initialize(){
            dict[NameKey] = "Ryan";
        }
    }
    
    class HealthSystem {
        Key<int> Health = new Key<Health>();
        public void InitHealth(BaseEntity entity){
            entity.dict[Health] = 20;
        }
    
        public void DamageEntity(BaseEntity entity, int damage){
            entity.dict[Health] = entity.dict[Health] - damage];
        }
    }
    

    因此,从SmartDict获取值取决于您是否有权访问键对象。对于用户授权或确保人们不会弄乱他们应该使用外观的上下文中的数据很有用。

    您可以使用对象字典,只需记住您输入的类型,但我正试图制作一些不太可能出错的东西,并且最好使用WCF进行序列化(但我假设这是另一个问题,需要提前注册兼容类型等,并使用GUID以便在反序列化后匹配键)。

    我已经介绍了ConditionalWeakTable,但它也有一些弱引用,考虑到我希望能够序列化它,这些引用可能并不总是需要的。

    我的第一次尝试没有真正理解泛型出了什么问题。

    class HMap<K> where K : Key<?>
    {
        ConditionalWeakTable<K, object> data = new ConditionalWeakTable<K, object>();
    
        public T this[Key<T> index]
        {
            get
            {
                T ret;
                var success = data.TryGetValue(index, out ret);
                if (!success) throw new KeyNotFoundException("Key not found: " + index);
                return ret;
            }
            set
            {
                data.Add(index, value);
            }
        }
    }
    
    2 回复  |  直到 6 年前
        1
  •  2
  •   Kirill Shlenskiy    6 年前

    使用索引器不可能实现您想要的内容(因为在.NET中无法使用通用索引器),但如果您愿意使用通用方法与 SmartDict 相反,您可以通过最少的努力来实现类似的API:

    SmartDict dict = new SmartDict();
    Key<string> nameKey = new Key<string>("name");
    Key<int> idKey = new Key<int>("id");
    
    dict.Set(nameKey, "Ryan");
    dict.Set(idKey, 123);
    
    string name = dict.Get(nameKey); // name is now "Ryan".
    int id = dict.Get(idKey); // id is now 123.
    

    SmartDict 实施:

    internal interface IKey
    {
        string Name { get; }
    }
    
    public sealed class Key<T> : IKey
    {
        public string Name { get; }
    
        public Key(string name)
        {
            Name = name;
        }
    }
    
    public sealed class SmartDict
    {
        private readonly Dictionary<IKey, object> Values = new Dictionary<IKey, object>();
    
        public T Get<T>(Key<T> key)
        {
            if (Values.TryGetValue(key, out object value)) {
                return (T)value;
            }
    
            throw new KeyNotFoundException($"'{key.Name}' not found.");
        }
    
        public void Set<T>(Key<T> key, T value)
        {
            Values[key] = value;
        }
    }
    

    由于所有值最终都存储为 object ,可能会导致装箱-如果性能成为问题,您可以稍后解决此问题。

        2
  •  0
  •   H.J. Meijer    6 年前

    也许您不应该依赖于对象的类型,而应该使用(大)枚举来定义中的类型。然后你可以用字典来存储它。

    public enum types{
        Name,
        Health
    }
    

    然后您可以使用:

    Dictionary<types, string>
    

    管理您的数据