确保对象不为 null

发布于 2024-12-14 02:24:50 字数 2484 浏览 4 评论 0原文

如何确保类的某个实例永远不会为空?有人告诉我使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

穿透光 2024-12-21 02:24:50

我认为您需要了解 instance1 和随后的 property1 将如何实例化,并且仅以它们不能为空的方式实例化它们。这通常是通过在构造时检查参数来完成的,例如:

public instance1(string property1)
{
    if (property1 == null) throw new ArgumentNullException("property1");

    this.property1 = property1;
}

如果您以不能以无效状态存在的方式创建类型,则可以确保您的依赖代码不会陷入 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; }
}

在我的示例类型中,我要求我的ForenameSurname 值具有非空值。这是通过我的构造函数强制执行的...我的 Person 类型永远不能用 null 值实例化(尽管空值可能同样糟糕,因此检查 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; }
}

My Person code> type 仍然强制执行操作所需的字段,但引入了可选字段。然后,在执行使用这些成员的操作时,我需要考虑到这一点:(

public override ToString()
{
  return Forename + (Initial == null ? String.Empty : " " + Initial) + " " + Surname;
}

尽管这不是 ToString 的最佳示例)。

I think you need to understand how instance1, and subsequently property1 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.:

public instance1(string property1)
{
    if (property1 == null) throw new ArgumentNullException("property1");

    this.property1 = property1;
}

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.:

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; }
}

In my example type, I'm requiring that my Forename and Surname value have a non-null value. This is enforced through my constructor... my Person type can never be instantiated with null values (although, perhaps empty values are just as bad, so checking IsNullOrWhiteSpace and throwing an appropriate ArgumentException 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:

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; }
}

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:

public override ToString()
{
  return Forename + (Initial == null ? String.Empty : " " + Initial) + " " + Surname;
}

(Although that is not the greatest example of a ToString).

姐不稀罕 2024-12-21 02:24:50

您可以使用:

if ( instance1 != null && instance1.property1.Equals("bla")){
   // Your code 
 } 

You can use:

if ( instance1 != null && instance1.property1.Equals("bla")){
   // Your code 
 } 
不可一世的女人 2024-12-21 02:24:50

就我个人而言,我会使用 ??运算符(假设property1是一个字符串)

public string MyString
{
    get { instance1.property1 ?? "Default value"; }
}

Personally, I would use the ?? operator (assuming property1 is a string)

public string MyString
{
    get { instance1.property1 ?? "Default value"; }
}
甜味拾荒者 2024-12-21 02:24:50

人们通常通过以下三种方式之一来处理这种情况。最糟糕的方法(在我看来)是对您看到的每个引用都保持偏执,总是针对 null 进行测试,然后如果确实遇到 null 则执行“某事”。这种方法的问题在于,您经常深入某些调用树,因此您所做的“某事”(例如返回“合理的”默认值)不仅可能是分层违规,但也可能掩盖问题而不是直面问题。在这些情况下,实际上可能更好的是让 NullReferenceException 被抛出,而不是做出一些半途而废的尝试继续。

更明智的做法是建立一个编码约定,其中引用永远不会为空,除非在少数情况下,从上下文中可以明显看出它们可以为空。此外,只要有可能,就可以使类不可变或大部分不可变,以便所有不变量都可以在构造函数中完成,并且其余代码可以继续其生命。例如,我可能会写:

public class Person {
  private readonly string firstName;
  private readonly string lastName;
  private readonly Nubbin optionalNubbin;
}

...从名称中可以清楚地看出,OptionalNubbin 可能为 null。

最后也是最根本的方法是编写不允许 null 的代码。您可以发明 Nullable的对偶,即:

public struct NonNullable<T> {
  ...
}

实现可以以几种不同的方式工作(通过使用显式 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:

public class Person {
  private readonly string firstName;
  private readonly string lastName;
  private readonly Nubbin optionalNubbin;
}

...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:

public struct NonNullable<T> {
  ...
}

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.

昔梦 2024-12-21 02:24:50

由于 instance1.property1 永远不应该为 null,因此请查看是否有办法正确初始化它,然后在有人尝试将其设置为 null 时抛出 ArgumentNullException

例子:

public string Property1
{
    set 
    {
      if(value == null)
      {
        throw new ArgumentNullException();
      } 
      instance1.property1 = value;
    }
}

Since instance1.property1 should never be null, see if there's a way to initialize it properly, then thrown an ArgumentNullException if someone tries to set it to null.

Example:

public string Property1
{
    set 
    {
      if(value == null)
      {
        throw new ArgumentNullException();
      } 
      instance1.property1 = value;
    }
}
℉服软 2024-12-21 02:24:50

你可以做如下的事情。

public string MyString
{
    get
    {
        if(instance!=null && instance1.property1.Equals("bla"))
        {
            return "bla"; 
        }
        else 
        {
            return String.Empty; 
        }
    }
}

这基本上将首先检查实例是否为空。

you can do something like below.

public string MyString
{
    get
    {
        if(instance!=null && instance1.property1.Equals("bla"))
        {
            return "bla"; 
        }
        else 
        {
            return String.Empty; 
        }
    }
}

This will basically check first whether instance is null or not.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文