我的代码如下:
#nullable enable
class MyClass<KEY, ITEM>
{
readonly Dictionary<KEY, ITEM> Map = new Dictionary<KEY, ITEM>();
public void Process(KEY key, ITEM item)
{
if (key != null)
{
Map[key] = item;
}
}
}
#nullable disable
编译器对此并不感到兴奋,它给了我警告
type 'KEY' cannot be used as type parameter 'TKey' in the generic type or method 'Dictionary<TKey, TValue>
我当然可以理解。问题是,将'key'参数的null发送到Process()是完全有效的,因此我无法在类中添加“ where KEY:notnull”约束。 (并且MyClass需要接受KEY类型参数的类和结构)
我唯一想到的是:
#nullable enable
class MyClass<KEY, ITEM>
{
#nullable disable
readonly Dictionary<KEY, ITEM> Map = new Dictionary<KEY, ITEM>();
#nullable enable
public void Process(KEY key, ITEM item)
{
if (key != null)
{
Map[key] = item;
}
}
}
#nullable disable
这让编译器保持满意,但是然后我没有所有那些不错的C#8空检查。例如,它允许我编写以下代码:
Map[default] = item;
而且编译器也没有引起注意。
我如何告诉编译器,Dictionary <>的'KEY'类型参数应禁止使用null,但在外部类中仍允许KEY值为null?
编辑
我想使用新的C#8可空性功能,以便在编译时捕获尽可能多的空指针(而不是等待运行时异常)。
进一步编辑
我现在的方向是在Dictionary上放一层薄薄的纸,以强制执行null限制,并使用它代替Dictionary <>
#nullable enable
public class CheckDictionary<KEYTYPE, VALUETYPE>
{
#nullable disable
readonly Dictionary<KEYTYPE, VALUETYPE> Dictionary = new Dictionary<KEYTYPE, VALUETYPE>();
#nullable enable
public VALUETYPE this[[DisallowNull] KEYTYPE key]
{
get { return Dictionary[key]; }
set { Dictionary[key] = value; }
}
public bool Remove([DisallowNull] KEYTYPE key)
{ return Dictionary.Remove(key); }
public bool TryGetValue([DisallowNull] KEYTYPE key, out VALUETYPE value)
{ return Dictionary.TryGetValue(key, out value); }
public List<VALUETYPE> Values => Dictionary.Values.ToList();
}
答案 0 :(得分:1)
我认为在您的情况下,可以使用下一种方法:
TKey
约束为notnull
。结果,编译器将针对TKey
实施null检查。AllowNullAttribute
添加到方法TKey key
的参数Process
中。结果,将null
key
传递给方法Process
的结果代码将不会产生警告。以下是带有注释的代码:
class MyClass<TKey, TItem> where TKey : notnull
{
// With "notnull" constraint type parameter "TKey" matches type constraint
// of the class Dictionary<TKey, TValue>, therefore compiler does not
// generate the next warning:
// The type 'TKey' cannot be used as type parameter 'TKey' in the
// generic type or method 'Dictionary<TKey, TValue>'. Nullability
// of type argument 'TKey' doesn't match 'notnull' constraint.
readonly Dictionary<TKey, TItem> Map = new Dictionary<TKey, TItem>();
public void Process([System.Diagnostics.CodeAnalysis.AllowNull] TKey key, TItem item)
{
// "TKey key" is marked with [AllowNull] attribute. Therefore if you delete
// null check "key != null" compiler will produce the next warning on the line
// "Map[key] = item":
// Possible null reference argument for parameter 'key' in
// 'TItem Dictionary<TKey, TItem>.this[TKey key]'.
if (key != null)
Map[key] = item;
// Because "TKey" is constrained to be "notnull", this line of code
// produces the next warning:
// Possible null reference argument for parameter 'key' in
// 'TItem Dictionary<TKey, TItem>.this[TKey key]'.
Map[default] = item;
}
}
static class DemoClass
{
public static void Demo()
{
MyClass<string, int> mc1 = new MyClass<string, int>();
// This line does not produce a warning, because "TKey key" is marked
// with [AllowNull] attribute.
mc1.Process(null, 0);
// This line does not produce a warning too.
mc1.Process(GetNullableKey(), 0);
// Usage of "MyClass" with value type "TKey" is also allowed.
// Compiler does not produce warnings.
MyClass<int, int> mc2 = new MyClass<int, int>();
mc2.Process(0, 1);
}
public static string? GetNullableKey() => null;
}
因此,使用这种方法:
TKey
中的MyClass
进行了空检查; null
key
传递给Process
方法。答案 1 :(得分:0)
我发现了同样的问题,我的解决方案是将键包装在一个 1 元组中:
class MyClass<TKey, TItem>
{
readonly Dictionary<ValueTuple<TKey>, TItem> Map = new Dictionary<ValueTuple<TKey>, TItem>();
public void Process(TKey key, TItem item)
{
Map[ValueTuple.Create(key)] = item;
}
}
通过这种方式,可以将任何值添加到字典中(即 null),并且编译器无需禁用规则即可满足要求。