I have this code:
我有这样的代码:
private static string? _foo;
private static void Step1()
{
if (_foo is null) { return; }
Step2();
}
private static void Step2()
{
Console.WriteLine(_foo.Length); // This warns of Dereference of a possibly null reference
}
What I would like to do is something like what the MemberNotNull
attribute does, but instead of promising a member is not null after the method, it instead promises that the member is not null at the moment the method is called.
我想做的是类似于PadderNotrings属性所做的事情,但不是在方法之后承诺成员不为null,而是在方法被调用时承诺成员不为null。
So if I could attribute my method like [MemberNotNullBefore(nameof(_foo))] private static void Step2()
and then instead of the warning happening inside that method, if I removed the first line below it should warn me that _foo
is possibly null next to the method call:
因此,如果我可以将我的方法设置为[MemberNotNullBeever(nameof(_Foo))]Private Static void Step2(),然后不是在该方法内部出现警告,如果我删除了下面的第一行,它应该警告我方法调用旁边的_foo可能为空:
if (_foo is null) { return; }
Step2(); // This should warn that _foo is possibly null if the first line is removed
I know I could just accept _foo
as an argument for the Step2
method but is there a way to achieve this using nullability attributes from C# 8?
我知道我可以只接受_foo作为Step2方法的参数,但是有没有办法使用C#8中的可空性属性来实现这一点呢?
更多回答
I think passing arguments is the most appropriate solution in this case unless we can find a way to follow the nullable state multiple levels deeper in order.
我认为在这种情况下,传递参数是最合适的解决方案,除非我们能找到一种方法来跟踪多个层次的可空状态。
优秀答案推荐
You could use the pattern
你可以用这个模式
private static string? _foo;
public static bool TryStep1([MaybeNullWhen(false)] out string value)
{
value = _foo;
return _foo is not null;
}
private static void Step2(string foo)
{
Console.WriteLine(foo.Length); // foo is not nullable -> no warning
}
And then use like this:
然后像这样使用:
if (TryStep1(out var foo)) {
Step2(foo);
}
Note that the [MaybeNullWhen(false)]
attribute supresses the message "_foo
may be null here".
请注意,[MaybeNullWhen(False)]属性抑制消息“_foo此处可能为空”。
Maybe the field _foo
isn't required anymore, if the value can be passed from one method to the next directly.
如果值可以直接从一个方法传递到下一个方法,那么可能不再需要field_foo。
A possible solution is adding an assertion at the top of the method: Debug.Assert(_foo is not null);
.
This clearly encodes a program invariant, enforces it in DEBUG code and removes the warning on the subsequent Console.WriteLine(foo.Length);
一种可能的解决方案是在方法的顶部添加断言:Debug.Assert(_foo不为空);。这清楚地编码了程序不变量,在调试代码中强制执行它,并删除了后续Console.WriteLine(foo.Length)上的警告;
更多回答
Sorry to say, but if still had to pass an argument to Step2()
then if (_foo != null) Step2(_foo);
I think it might just do the same :)
抱歉地说,如果仍然必须将参数传递给Step2(),那么如果(_foo!=NULL)Step2(_Foo);我认为它可能会做同样的事情:)
@AqibChattha: note that the argument passed to Step2
is not nullable. There will be no warning in Step2
. This pattern allows a logical transition from one step to the next without an additional _foo != null
. It may even allow to remove the _foo
field completely.
@AqibChattha:请注意,传递给Step2的参数不能为空。在步骤2中将不会出现任何警告。此模式允许从一个步骤到下一个步骤的逻辑转换,而不需要额外的_foo!=NULL。它甚至可能允许完全删除_foo字段。
Sorry, it is not an additional condition as it is directly being called in Step1()
, and since the argument Step2()
accepts is not nullable, so still there will be no warnings. My point is that the question does not allow the use of arguments and only attributes, and if we can use arguments there are very easy and straightforward methods so why complicate it :>
抱歉,这不是附加条件,因为它是在Step1()中直接调用的,而且由于Step2()接受的参数不可为空,因此仍然不会有任何警告。我的观点是,这个问题不允许使用参数和仅使用属性,如果我们可以使用参数,那么有非常简单和直接的方法,为什么要复杂化:>
The OP's solution requires an additional if != null
or !
inside Step2
to get rid of the warning.
OP的解决方案需要额外的if!=NULL或!在Step2中删除该警告。
I think you misunderstood, I am referring to: private static void Step1() { if (_foo != null) Step2(_foo); } private static void Step2(string foo) { /* use foo here */ }
now using foo
will not generate a warning as it is not a nullable argument. It also reduces the unnecessary steps involved and follows the KISS principle.
我认为您误解了,我指的是:私有静态空Step1(){if(_foo!=NULL)Step2(_Foo);}私有静态空Step2(字符串foo){/*在这里使用foo*/}现在使用foo不会生成警告,因为它不是一个可以为空的参数。它还减少了不必要的步骤,并遵循接吻原则。
我是一名优秀的程序员,十分优秀!