C#:通过异构字典公开类型安全 API
C#: Exposing type safe API over heterogeneous dictionary
我想在特定 JSON 格式上公开类型安全 API。这基本上是我到目前为止所拥有的:
public class JsonDictionary
{
Dictionary<string, Type> _keyTypes = new Dictionary<string, Type> {
{ "FOO", typeof(int) },
{ "BAR", typeof(string) },
};
IDictionary<string, object> _data;
public JsonDictionary()
{
_data = new Dictionary<string, object>();
}
public void Set<T>(string key, T obj)
{
if (typeof(T) != _keyTypes[key])
throw new Exception($"Invalid type: {typeof(T)} vs {_keyTypes[key]}");
_data[key] = obj;
}
public dynamic Get(string key)
{
var value = _data[key];
if (value.GetType() != _keyTypes[key])
throw new Exception($"Invalid type: {value.GetType()} vs {_keyTypes[key]}");
return value;
}
}
可以很好地用作:
JsonDictionary d = new JsonDictionary();
d.Set("FOO", 42);
d.Set("BAR", "value");
但是读取值有点令人失望并且依赖于后期绑定:
var i = d.Get("FOO");
var s = d.Get("BAR");
Assert.Equal(42, i);
Assert.Equal("value", s);
有没有我可以用来实现类型安全泛型 Get<T>
而不是依赖 dynamic
的 C# 魔术(理想情况下应该在编译时检查类型)?我还想使用 Set<T>
的模式,以便 d.Set("BAR", 56);
触发编译警告。
Dictionary<string, Type> _keyTypes
如果需要可以做成static
。以上只是正在进行的工作。
我会将 T 转换为对象并使用 .GetType()
检查对象类型
public class JsonDictionary
{
Dictionary<string, Type> _keyTypes = new Dictionary<string, Type> {
{ "FOO", typeof(int) },
{ "BAR", typeof(string) },
};
IDictionary<string, object> _data;
public JsonDictionary()
{
_data = new Dictionary<string, object>();
}
public void Set(string key, object obj)
{
if (obj.GetType() != _keyTypes[key])
throw new Exception($"Invalid type: {obj.GetType()} vs {_keyTypes[key]}");
_data[key] = obj;
}
public object Get(string key)
{
return _data[key];
}
}
我这样试过,成功了:
JsonDictionary d = new JsonDictionary();
d.Set("FOO", 42);
d.Set("BAR", "value");
var i = d.Get("FOO");
var s = d.Get("BAR");
Console.WriteLine(i);
Console.WriteLine(s);
但老实说,我不喜欢你想要实现的目标。
我使用的解决方案与此类似:
public class JsonDictionary
{
public static readonly Key<int> Foo = new Key<int> { Name = "FOO" };
public static readonly Key<string> Bar = new Key<string> { Name = "BAR" };
IDictionary<string, object> _data;
public JsonDictionary()
{
_data = new Dictionary<string, object>();
}
public void Set<T>(Key<T> key, T obj)
{
_data[key.Name] = obj;
}
public T Get<T>(Key<T> key)
{
return (T)_data[key.Name];
}
public sealed class Key<T>
{
public string Name { get; init; }
}
}
我想在特定 JSON 格式上公开类型安全 API。这基本上是我到目前为止所拥有的:
public class JsonDictionary
{
Dictionary<string, Type> _keyTypes = new Dictionary<string, Type> {
{ "FOO", typeof(int) },
{ "BAR", typeof(string) },
};
IDictionary<string, object> _data;
public JsonDictionary()
{
_data = new Dictionary<string, object>();
}
public void Set<T>(string key, T obj)
{
if (typeof(T) != _keyTypes[key])
throw new Exception($"Invalid type: {typeof(T)} vs {_keyTypes[key]}");
_data[key] = obj;
}
public dynamic Get(string key)
{
var value = _data[key];
if (value.GetType() != _keyTypes[key])
throw new Exception($"Invalid type: {value.GetType()} vs {_keyTypes[key]}");
return value;
}
}
可以很好地用作:
JsonDictionary d = new JsonDictionary();
d.Set("FOO", 42);
d.Set("BAR", "value");
但是读取值有点令人失望并且依赖于后期绑定:
var i = d.Get("FOO");
var s = d.Get("BAR");
Assert.Equal(42, i);
Assert.Equal("value", s);
有没有我可以用来实现类型安全泛型 Get<T>
而不是依赖 dynamic
的 C# 魔术(理想情况下应该在编译时检查类型)?我还想使用 Set<T>
的模式,以便 d.Set("BAR", 56);
触发编译警告。
Dictionary<string, Type> _keyTypes
如果需要可以做成static
。以上只是正在进行的工作。
我会将 T 转换为对象并使用 .GetType()
检查对象类型public class JsonDictionary
{
Dictionary<string, Type> _keyTypes = new Dictionary<string, Type> {
{ "FOO", typeof(int) },
{ "BAR", typeof(string) },
};
IDictionary<string, object> _data;
public JsonDictionary()
{
_data = new Dictionary<string, object>();
}
public void Set(string key, object obj)
{
if (obj.GetType() != _keyTypes[key])
throw new Exception($"Invalid type: {obj.GetType()} vs {_keyTypes[key]}");
_data[key] = obj;
}
public object Get(string key)
{
return _data[key];
}
}
我这样试过,成功了:
JsonDictionary d = new JsonDictionary();
d.Set("FOO", 42);
d.Set("BAR", "value");
var i = d.Get("FOO");
var s = d.Get("BAR");
Console.WriteLine(i);
Console.WriteLine(s);
但老实说,我不喜欢你想要实现的目标。
我使用的解决方案与此类似:
public class JsonDictionary
{
public static readonly Key<int> Foo = new Key<int> { Name = "FOO" };
public static readonly Key<string> Bar = new Key<string> { Name = "BAR" };
IDictionary<string, object> _data;
public JsonDictionary()
{
_data = new Dictionary<string, object>();
}
public void Set<T>(Key<T> key, T obj)
{
_data[key.Name] = obj;
}
public T Get<T>(Key<T> key)
{
return (T)_data[key.Name];
}
public sealed class Key<T>
{
public string Name { get; init; }
}
}