C#Typesafe字典值取决于Key? IDictionary的<键<TValue>中,TValue&GT ;?

时间:2018-04-19 08:13:09

标签: c# generics

我不知道这个数据结构的正确名称(它是一个同构的地图吗?),但基本上我正试图得到类似的东西。

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];

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

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 个答案:

答案 0 :(得分:2)

使用索引器无法实现您想要的功能(因为您可以在.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,这可能导致装箱 - 如果性能成为问题,您可以稍后处理。

答案 1 :(得分:0)

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

public enum types{
    Name,
    Health
}

然后你可以使用:

Dictionary<types, string>

管理您的数据