我有一个函数被正确指定为返回一个可能为空的对象。我的代码调用该函数,但调用方式不会返回 null。
MyClass? MyFunction(string x);
/* ... */
var myObject = MyFunction("Never return null.");
myObject.MyMemberFunctionOfMyClass();
Visual Studio(正确地)将 myObject 的使用标记为“可能的空引用”。 我知道它永远不会为空,但编译器不知道。
有没有办法将其标记为已知不能为空?我知道我可以添加对 null 的测试,但这会重复编译器无论如何都会插入的 test-for-null/ throw-NullReferenceException 代码,并且如果没有它,我的函数将非常整洁。我也不想使用关闭警告的
#pragma
,因为我想保留其他值的警告。
我更喜欢某种方式将单个值包裹在“该值不会为空。继续。”的外衣中。
var myObject = MyFunction("Never return null.").NotNull();
有这样的事吗?
如果您确实确定某些内容不为 null,并且您不想为冗余的 null 检查付出性能成本,则可以随时使用
!
来抑制它。
var myObject = MyFunction("Never return null.")!;
您可以选择将其放入带有解释的包装函数中。
如果函数有时确实可以返回 null,那么也可以注释例如返回可能或可能不为 null 的条件。
[return: NotNullIfNotNull(nameof(input))]
public static string? Foo(string? input)
{
if (input == null) return null;
else return input + "bar";
}
public static void Test()
{
string a = Foo(null); // Warning
string b = Foo("hello"); // No warning
string? c = Foo(null); // No warning
string d = Foo(b); // No warning
string e = Foo(c); // Warning
}
然而,这些的可能性相当有限。
不只是用
!
进行抑制的另一种选择是制作一个不返回 null 的函数版本,并且如果给定的输入可能导致 null,则抛出(或者如果确实想避免释放性能成本,则可能断言)。在最简单的情况下,这可能是一个包装器。提供更多保护,而不仅仅是消除警告。
public static string? MaybeNull(string input) // 3rd party thing you can't change
{
if (input.Length < 5) return null;
else return input;
}
public static string NeverNull(string input)
{
if (input.Length < 5) throw new ArgumentException("Must be at least 5 characters.", nameof(input));
string? ret = MaybeNull(input);
Debug.Assert(ret != null);
return ret!;
}
public static string NeverNull2(string input)
{
string? ret = MaybeNull(input);
if (ret == null) throw new ArgumentException("Invalid input.", nameof(input));
return ret;
}