【发布时间】:2021-09-08 06:13:13
【问题描述】:
正如上游记录的那样,不能使用“数组”作为基本约束:
[...]Some types are disallowed as a base class constraint: Object, Array, and ValueType.[...]
然而,数组的类型推断似乎很少,如下所示:
我的目标是扩展原来的 SO 帖子,同时处理数组类型:
所以我的幼稚尝试如下:
public class JsonDictionary
{
public static readonly Key<int> Int = new Key<int> { Name = "INT" };
public static readonly Key<int[]> Int3 = new Key<int[]> { Name = "INT3" };
IDictionary<string, object> _data;
public JsonDictionary()
{
_data = new Dictionary<string, object>();
}
public void Set<T>(Key<T> key, T obj)
{
if (obj is int[] objArray) // FIXME: runtime check
{
if (objArray.Length != 3)
throw new FormatException("Illegal INT3");
}
_data[key.Name] = obj;
}
public T Get<T>(Key<T> key)
{
return (T)_data[key.Name];
}
public class Key<T>
{
public string Name { get; init; }
}
}
用法很简单:
var d = new JsonDictionary();
d.Set(JsonDictionary.Int, 42);
var i = d.Get(JsonDictionary.Int);
d.Set(JsonDictionary.Int3, new int[] { 1, 2, 3 });
var i3 = d.Get(JsonDictionary.Int3);
Assert.Throws<FormatException>(() => d.Set(JsonDictionary.Int3, new int[] { 1, 2 }));
请注意我如何使用运行时检查 (obj is int[] objArray),因为我无法对“数组”使用某种约束。
有没有办法重写上面的,这样我就可以有两个不同的Set 函数,一个用于T,一个用于T[]。否则我需要用丑陋的 if/else 来处理所有可能的类型:
if (obj is int[] objArray)
{
if (objArray.Length != 3)
throw new FormatException("Illegal INT3");
}
else if (obj is ushort[] objArray)
{
if (objArray.Length != 3)
throw new FormatException("Illegal USHORT3");
}
else if (obj is double[] objArray)
{
if (objArray.Length != 3)
throw new FormatException("Illegal DOUBLE3");
}
[...]
【问题讨论】:
-
澄清一下:您是在问如何创建一个对输入作为数组进行约束的泛型方法,还是在问如何确定一个变量是否包含一个数组?
-
考虑创建自定义类型来表示约束的替代方法。 使非法代表成为不可能
-
@Llama 我同意,但是由于 OP 要求 generic 函数,所以
string也应该是有效的。否则他一开始就不应该使用泛型。 -
"有没有办法重写上面的代码,这样我就可以拥有两个不同的
Set函数,一个用于T,一个用于T[]" 我很确定重载分辨率会选择如果您传递数组类型,则数组重载,因此您应该能够编写另一个重载,例如public void Set<T>(Key<T[]> key, T[] obj)。 (this is also the answer to one of your linked posts) 是什么阻止你这样做? -
请添加一些关于约束应该实际匹配的类型的信息。例如
string[]呢?List<int>也可以吗?还是DateTime[]?问问自己这些类型有什么共同点。