如何解决关于 DisallowNull 的 CS8607 警告?
How to address CS8607 warning about DisallowNull?
在 .NET 5 class 库中考虑此 C# class,并启用 nullable reference types 功能 :
public class ContraMapComparer<T, T1> : IEqualityComparer<T1>
{
private readonly IEqualityComparer<T> source;
private readonly Func<T1, T> selector;
public ContraMapComparer(IEqualityComparer<T> source, Func<T1, T> selector)
{
this.source = source;
this.selector = selector;
}
public bool Equals(T1? x, T1? y)
{
if (x is null && y is null)
return true;
if (x is null || y is null)
return false;
return source.Equals(selector(x), selector(y));
}
public int GetHashCode([DisallowNull] T1 obj)
{
return source.GetHashCode(selector(obj));
}
}
[DisallowNull]
属性由 Visual Studio 的 启用界面 快速操作添加。
编译时,编译器发出此警告:
CS8607 A possible null value may not be used for a type marked with [NotNull] or [DisallowNull]
显然,如果您启用了将警告视为错误(我有),这意味着代码无法编译。
如何解决这个问题?
我试过向 obj
、source
和 selector
添加 运行 次空守卫,但这没有帮助。我也尝试将 [DisallowNull]
属性添加到 source
和 selector
,但这也没有帮助。
为 [DisallowNull]
阅读 the documentation 让我 none 变得更聪明。
即使删除 [DisallowNull]
属性也无法解决问题。编译器警告仍然存在。
我能够识别的唯一修复是 #pragma
来抑制警告:
#pragma warning disable CS8607 // A possible null value may not be used for a type marked with [NotNull] or [DisallowNull]
return source.GetHashCode(selector(obj));
#pragma warning restore CS8607 // A possible null value may not be used for a type marked with [NotNull] or [DisallowNull]
还有其他修复方法吗?
Func<T1,T>
未注释为不是 return null
。引入一个支持该功能的新代表:
[return:NotNull]
public delegate T NonNullFunc<in T1, out T>(T1 value);
public class ContraMapComparer<T, T1> : IEqualityComparer<T1>
{
private readonly IEqualityComparer<T> source;
private readonly NonNullFunc<T1, T> selector;
public ContraMapComparer(IEqualityComparer<T> source, NonNullFunc<T1, T> selector)
{
//As before
这比允许空值或使用 pragma 更好,因为它应该强制使用任何表达式来定义 selector
,它不会 return null
.
(您可能还希望对委托的输入参数进行注释以禁止空值)
警告不是在谈论 [DisallowNull]
方法参数的 [DisallowNull]
属性。它正在谈论 source.GetHashCode
调用!毕竟这个调用也是在调用IEqualityComparer.GetHashCode
,它有[DisallowNull]
属性
selector(obj)
returns a T
,但是 T
对它没有限制,所以它可以是可空类型,如 string?
或 int?
。如果它是可空类型,则它可以为空。但是 source.GetHashCode
不允许空值!因此警告。
I've tried adding run-time null guards to obj
, source
, and selector
您应该检查 selector(obj)
,而不是 source
、selector
或 obj
。 selector(obj)
是可以为null的东西,这里不允许为null。
T t = selector(obj);
if (t == null) {
throw new ArgumentException("obj maps to a null!", nameof(obj));
}
return source.GetHashCode(t);
虽然我很欣赏前面两个解释问题的答案,但我发现 none 的建议解决方案是最佳的。
- Throwing an exception in
GetHashCode
is forbidden。 (不是很正式的文档,但对于 Eric Lippert,它已经足够接近了。)
- 使用自定义委托会使 API 的便携性降低。
幸运的是,Jeroen Mostert 在评论中提出了一个更好的解决方案:Constrain T
to be notnull
:
public class ContraMapComparer<T, T1> : IEqualityComparer<T1> where T : notnull
我就是这么做的,解决了这个问题。
在 .NET 5 class 库中考虑此 C# class,并启用 nullable reference types 功能 :
public class ContraMapComparer<T, T1> : IEqualityComparer<T1>
{
private readonly IEqualityComparer<T> source;
private readonly Func<T1, T> selector;
public ContraMapComparer(IEqualityComparer<T> source, Func<T1, T> selector)
{
this.source = source;
this.selector = selector;
}
public bool Equals(T1? x, T1? y)
{
if (x is null && y is null)
return true;
if (x is null || y is null)
return false;
return source.Equals(selector(x), selector(y));
}
public int GetHashCode([DisallowNull] T1 obj)
{
return source.GetHashCode(selector(obj));
}
}
[DisallowNull]
属性由 Visual Studio 的 启用界面 快速操作添加。
编译时,编译器发出此警告:
CS8607 A possible null value may not be used for a type marked with [NotNull] or [DisallowNull]
显然,如果您启用了将警告视为错误(我有),这意味着代码无法编译。
如何解决这个问题?
我试过向 obj
、source
和 selector
添加 运行 次空守卫,但这没有帮助。我也尝试将 [DisallowNull]
属性添加到 source
和 selector
,但这也没有帮助。
为 [DisallowNull]
阅读 the documentation 让我 none 变得更聪明。
即使删除 [DisallowNull]
属性也无法解决问题。编译器警告仍然存在。
我能够识别的唯一修复是 #pragma
来抑制警告:
#pragma warning disable CS8607 // A possible null value may not be used for a type marked with [NotNull] or [DisallowNull]
return source.GetHashCode(selector(obj));
#pragma warning restore CS8607 // A possible null value may not be used for a type marked with [NotNull] or [DisallowNull]
还有其他修复方法吗?
Func<T1,T>
未注释为不是 return null
。引入一个支持该功能的新代表:
[return:NotNull]
public delegate T NonNullFunc<in T1, out T>(T1 value);
public class ContraMapComparer<T, T1> : IEqualityComparer<T1>
{
private readonly IEqualityComparer<T> source;
private readonly NonNullFunc<T1, T> selector;
public ContraMapComparer(IEqualityComparer<T> source, NonNullFunc<T1, T> selector)
{
//As before
这比允许空值或使用 pragma 更好,因为它应该强制使用任何表达式来定义 selector
,它不会 return null
.
(您可能还希望对委托的输入参数进行注释以禁止空值)
警告不是在谈论 [DisallowNull]
方法参数的 [DisallowNull]
属性。它正在谈论 source.GetHashCode
调用!毕竟这个调用也是在调用IEqualityComparer.GetHashCode
,它有[DisallowNull]
属性
selector(obj)
returns a T
,但是 T
对它没有限制,所以它可以是可空类型,如 string?
或 int?
。如果它是可空类型,则它可以为空。但是 source.GetHashCode
不允许空值!因此警告。
I've tried adding run-time null guards to
obj
,source
, andselector
您应该检查 selector(obj)
,而不是 source
、selector
或 obj
。 selector(obj)
是可以为null的东西,这里不允许为null。
T t = selector(obj);
if (t == null) {
throw new ArgumentException("obj maps to a null!", nameof(obj));
}
return source.GetHashCode(t);
虽然我很欣赏前面两个解释问题的答案,但我发现 none 的建议解决方案是最佳的。
- Throwing an exception in
GetHashCode
is forbidden。 (不是很正式的文档,但对于 Eric Lippert,它已经足够接近了。) - 使用自定义委托会使 API 的便携性降低。
幸运的是,Jeroen Mostert 在评论中提出了一个更好的解决方案:Constrain T
to be notnull
:
public class ContraMapComparer<T, T1> : IEqualityComparer<T1> where T : notnull
我就是这么做的,解决了这个问题。