Amc*_*tty 0 c# coding-style exception-safety
如何确保某个类的某个实例永远不会为null?有人告诉我使用Debug.Assert(),但这样做,我只会确保代码在调试模式下工作,而我想确保在发布中的is-never-null条件.
例如,在过去我编写的代码如下:
public string MyString
{
get
{
if(instance1.property1.Equals("bla"))
{
return bla;
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是如果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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我用这个方法来调用
_authenticationResult = authObj.CheckUser();
Run Code Online (Sandbox Code Playgroud)
我也有这个属性
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 }
Run Code Online (Sandbox Code Playgroud)
发生的事情是_authenticationResult为null一次,并且属性AuthResult在尝试"null.auth"时抛出了nullref.我怎样才能确保(可能在CheckUser()方法中)它永远不会返回null.
当我调试应用程序时,它从未发生过.但在生产中,当服务器超时时,有时该方法返回null.
谢谢,
我认为您需要了解如何instance1以及随后property1将要实例化,并且只能以不能为空的方式实例化它们.这通常通过检查构造中的参数来完成,例如:
public instance1(string property1)
{
if (property1 == null) throw new ArgumentNullException("property1");
this.property1 = property1;
}
Run Code Online (Sandbox Code Playgroud)
如果您创建类型的方式使它们不能以无效状态存在,那么您可以确保依赖代码不会落在null值上.
否则,我们需要看一个更全面的例子来说明你正在做些什么来给你更具体的建议.
另一件需要考虑的事情是,您的类可以存在哪种状态是必需的操作状态,而不是可选的操作状态.也就是说,您的班级需要哪些成员来操作,您应该努力设计您的班级,使他们始终具有所需的状态,例如:
public class Person
{
public Person(string forename, string surname)
{
if (forename == null) throw new ArgumentNullException("forename");
if (surname == null) throw new ArgumentNullException("surname");
Forename = forename;
Surname = surname;
}
public string Forename { get; private set; }
public string Surname { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)
在我的示例类型中,我要求my Forename和Surnamevalue具有非null值.这是通过我的构造函数强制执行的......我的Person类型永远不能用空值实例化(尽管,也许空值也一样糟糕,所以检查IsNullOrWhiteSpace并抛出一个合适ArgumentException的路径,但让我们保持简单).
如果我要引入一个可选字段,我会允许它改变我的Person实例的状态,例如,给它一个setter:
public class Person
{
public Person(string forename, string surname)
{
if (forename == null) throw new ArgumentNullException("forename");
if (surname == null) throw new ArgumentNullException("surname");
Forename = forename;
Surname = surname;
}
public string Forename { get; private set; }
public string Surname { get; private set; }
public string Initial { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我的Person类型仍然强制执行操作所需的字段,但引入了一个可选字段.然后,我需要在执行使用这些成员的操作时考虑到这一点:
public override ToString()
{
return Forename + (Initial == null ? String.Empty : " " + Initial) + " " + Surname;
}
Run Code Online (Sandbox Code Playgroud)
(虽然这不是一个最好的例子ToString).