确保对象不为 null
如何确保类的某个实例永远不会为空?有人告诉我使用 Debug.Assert() 但这样做,我只能确保代码在调试模式下工作,而我也想确保发布中的 is-never-null 条件。
例如,过去我写过这样的代码:
public string MyString
{
get
{
if(instance1.property1.Equals("bla"))
{
return bla;
}
}
}
但是如果instance1为null,则会抛出异常。我希望将来避免犯这样的错误并产生这样的异常。
谢谢,
请参阅下面的具体示例来说明问题:
我有一种根据服务器响应对用户进行身份验证的方法。方法是这样的:
/// <summary>
/// attempts authentication for current user
/// </summary>
/// <returns></returns>
public AuthResult CheckUser()
{
WebRequest request = WebRequest.Create(GetServerURI);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
string postdata = "data=" + HttpUtility.UrlEncode(SerializeAuth());
byte[] arr = Utils.AppDefaultEncoding.GetBytes(postdata);
request.ContentLength = arr.Length;
request.Timeout = Convert.ToInt32(TimeUtils.GetMiliseconds(10, TimeUtils.TimeSelect.Seconds));
Stream strToWrite = request.GetRequestStream();
strToWrite.Write(arr, 0, arr.Length);
WebResponse response = request.GetResponse();
using (Stream dataFromResponse = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(dataFromResponse))
{
string readObj = reader.ReadToEnd();
return DeserializeAuth(readObj);
}
}
}
要调用此方法,我使用
_authenticationResult = authObj.CheckUser();
我也有此属性,其中
public ResultType AuthResult
{
get
{
if (_authenticationResult.auth == "1")
return ResultType.Success;
if (_authenticationResult.auth == "0")
return ResultType.FailAccountExpired;
if (_authenticationResult.auth == "-1")
return ResultType.FailWrongUsernameOrPassword;
if (_authenticationResult.auth == "-2")
return ResultType.Banned;
return ResultType.NoAuthDone;
}
}
public enum ResultType { Success, FailWrongUsernameOrPassword, FailAccountExpired, NoAuthDone, Banned }
发生的情况是 _authenticationResult 为 null 一次,并且属性 AuthResult 在尝试“null.auth”时抛出 nullref。我如何确保(可能在 CheckUser() 方法内)它永远不会返回 null。
当我调试应用程序时,它从未发生过。但在生产中,当服务器超时时,该方法有时会返回 null。
谢谢,
How can I make sure that a certain instance of a class will never be null? Someone told me to use Debug.Assert() but by doing so, I would only ensure that the code works in debug mode, whereas I want to ensure the is-never-null condition in release as well.
For example, in the past I wrote code like:
public string MyString
{
get
{
if(instance1.property1.Equals("bla"))
{
return bla;
}
}
}
But this throws an exception if instance1 is null. I would like to avoid making such mistakes and generating such exceptions in the future.
Thanks,
please see a specific example below that illustrates the problem:
I have a method that authenticates users based on responses from a server. The method is this:
/// <summary>
/// attempts authentication for current user
/// </summary>
/// <returns></returns>
public AuthResult CheckUser()
{
WebRequest request = WebRequest.Create(GetServerURI);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
string postdata = "data=" + HttpUtility.UrlEncode(SerializeAuth());
byte[] arr = Utils.AppDefaultEncoding.GetBytes(postdata);
request.ContentLength = arr.Length;
request.Timeout = Convert.ToInt32(TimeUtils.GetMiliseconds(10, TimeUtils.TimeSelect.Seconds));
Stream strToWrite = request.GetRequestStream();
strToWrite.Write(arr, 0, arr.Length);
WebResponse response = request.GetResponse();
using (Stream dataFromResponse = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(dataFromResponse))
{
string readObj = reader.ReadToEnd();
return DeserializeAuth(readObj);
}
}
}
to call this method, i use
_authenticationResult = authObj.CheckUser();
I also have this property, among others
public ResultType AuthResult
{
get
{
if (_authenticationResult.auth == "1")
return ResultType.Success;
if (_authenticationResult.auth == "0")
return ResultType.FailAccountExpired;
if (_authenticationResult.auth == "-1")
return ResultType.FailWrongUsernameOrPassword;
if (_authenticationResult.auth == "-2")
return ResultType.Banned;
return ResultType.NoAuthDone;
}
}
public enum ResultType { Success, FailWrongUsernameOrPassword, FailAccountExpired, NoAuthDone, Banned }
what happened was that _authenticationResult was null once, and the property AuthResult threw a nullref at attempting "null.auth". How can I ensure (perhaps inside the CheckUser() method) that it never returns null.
When i debugged the app it never happened. But in production, when the server timed out sometimes the method returned null.
Thanks,
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我认为您需要了解
instance1
和随后的property1
将如何实例化,并且仅以它们不能为空的方式实例化它们。这通常是通过在构造时检查参数来完成的,例如:如果您以不能以无效状态存在的方式创建类型,则可以确保您的依赖代码不会陷入
null
价值观。否则,我们需要查看您正在做的事情的更完整示例,以便为您提供更具体的建议。
另一件需要考虑的事情是,您的类可以存在于什么状态,这是操作的必需状态,还是操作的可选状态。也就是说,您的类运行需要哪些成员,您应该努力设计您的类,使它们始终具有所需的状态,例如:
在我的示例类型中,我要求我的
Forename
和Surname
值具有非空值。这是通过我的构造函数强制执行的...我的Person
类型永远不能用 null 值实例化(尽管空值可能同样糟糕,因此检查IsNullOrWhiteSpace
并抛出一个适当的ArgumentException
是路线,但让我们保持简单)。如果我要引入一个可选字段,我将允许它改变我的
Person
实例的状态,例如,给它一个setter:My
Person
code> type 仍然强制执行操作所需的字段,但引入了可选字段。然后,在执行使用这些成员的操作时,我需要考虑到这一点:(尽管这不是 ToString 的最佳示例)。
I think you need to understand how
instance1
, and subsequentlyproperty1
are going to be instantiated, and only instantiate them in such a way that they cannot be null. This is generally done by checking arguments at construction, e.g.:If you create your types in such a way that they cannot exist in an invalid state, you ensure that your dependent code won't fall over on
null
values.Otherwise, we'd need to see a fuller example of what you are doing to give you more concrete advice.
The other thing to consider, is what state your class can exist in which is a required state of operation, vs. an optional state of operation. That being, what members are required for your class to operate, and you should endeavour to design your classes such that they always have the required state, e.g.:
In my example type, I'm requiring that my
Forename
andSurname
value have a non-null value. This is enforced through my constructor... myPerson
type can never be instantiated with null values (although, perhaps empty values are just as bad, so checkingIsNullOrWhiteSpace
and throwing an appropriateArgumentException
is the route, but lets keep it simple).If I were to introduce an optional field, I would allow it to mutate the state of my
Person
instance, e.g., give it a setter:My
Person
type still enforces the required fields for operation, but introduces an optional field. I then need to take this into consideration when performing an operation which uses these members:(Although that is not the greatest example of a
ToString
).您可以使用:
You can use:
就我个人而言,我会使用 ??运算符(假设
property1
是一个字符串)Personally, I would use the ?? operator (assuming
property1
is a string)人们通常通过以下三种方式之一来处理这种情况。最糟糕的方法(在我看来)是对您看到的每个引用都保持偏执,总是针对 null 进行测试,然后如果确实遇到 null 则执行“某事”。这种方法的问题在于,您经常深入某些调用树,因此您所做的“某事”(例如返回“合理的”默认值)不仅可能是分层违规,但也可能掩盖问题而不是直面问题。在这些情况下,实际上可能更好的是让 NullReferenceException 被抛出,而不是做出一些半途而废的尝试继续。
更明智的做法是建立一个编码约定,其中引用永远不会为空,除非在少数情况下,从上下文中可以明显看出它们可以为空。此外,只要有可能,就可以使类不可变或大部分不可变,以便所有不变量都可以在构造函数中完成,并且其余代码可以继续其生命。例如,我可能会写:
...从名称中可以清楚地看出,OptionalNubbin 可能为 null。
最后也是最根本的方法是编写不允许 null 的代码。您可以发明 Nullable的对偶,即:
实现可以以几种不同的方式工作(通过使用显式 Value 属性,或者可能使用运算符重载),但在任何情况下,NonNullable 的工作都是永远不要让某人将其设置为空。
People generally handle this situation in one of three ways. The worst way (in my opinion) is to be paranoid about every reference you look at, always testing it against null, and then doing ""something"" if you do encounter a null. The problem with such an approach is that you're often deep in some call tree, and so the "something" you do (like return a """reasonable""" default value) not only is likely to be a layering violation, but also is likely to paper over a problem rather than cause it to be confronted. In these cases it's actually probably better to let a NulLReferenceException be thrown rather than make some half-assed attempt to continue.
The saner thing to do is establish a coding convention where your references are never null, except in a few cases where it is obvious from context that they can be null. Additionally, and wherever possible, one can make one's classes immutable or mostly-immutable so that all the invariants can be done in the constructor and the rest of the code can get on with its life. For example, I might write:
...where it is clear from the name that optionalNubbin might be null.
The final and most radical approach is to write code that will not admit a null. You could invent the dual of Nullable<T>, namely:
The implementation could work in a few different ways (either by using an explicit Value property, or perhaps using operator overloading) but in any case the job of NonNullable is to never let someone set it to null.
由于
instance1.property1
永远不应该为 null,因此请查看是否有办法正确初始化它,然后在有人尝试将其设置为 null 时抛出ArgumentNullException
。例子:
Since
instance1.property1
should never be null, see if there's a way to initialize it properly, then thrown anArgumentNullException
if someone tries to set it to null.Example:
你可以做如下的事情。
这基本上将首先检查实例是否为空。
you can do something like below.
This will basically check first whether instance is null or not.