string.IsNullOrEmpty() 似乎不适用于类内类内的字符串

发布于 2024-10-21 07:18:08 字数 2776 浏览 1 评论 0原文

首先,我想我知道发生了什么事,但我想我应该把这个问题提出来进行一些讨论,看看除了我的想法之外是否有人对此有“答案”。因为,这对我来说完全没有意义。

我发现,当为异常创建错误日志时,我正在这样做,但它不起作用:

catch( Exception ex )
{
   LogException( ex.Message );
   if ( !string.IsNullOrEmpty( ex.InnerException.Message ) )
   {
      LogInnerException( ex.InnerException.Message );
   }
}

你瞧,当我运行这个时,我经常得到一个 NullReferenceException。啊?

我正在检查 null,对吗?

现在,我必须使用这个:

   if ( ex.InnerException != null && !string.IsNullOrEmpty( ex.InnerException.Message ) 

但这似乎违反直觉,而且也适得其反。因为,哎呀,如果我这样做:

   if ( !string.IsNullOrEmpty( null ) )

那根本不会给我带来任何问题。如果 ex.InnerException 为 null,那么 ex.InnerException.Message 肯定为 null,对吧?

显然不是。

我编写了一个完整的控制台应用程序来重现这一点。如果

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace stringisnullorempty
{
    class Program
    {
        static void Main( string[] args )
        {
            if ( !string.IsNullOrEmpty( null ) )
            {
                Console.WriteLine( "Ha ha ha, right...." );
            }

            MyBClass bClass = new MyBClass();
            bClass.BClassName = "Some B Class Name";
            if ( !string.IsNullOrEmpty( bClass.AClass.AString ) ) //<== Exception occurs here.
            {
                Console.WriteLine( bClass.AClass.AString );
            }
        }
    }

    public class MyAClass
    {
        private string aString;
        public string AString
        {
            get
            {
                return aString;
            }
            set
            {
                aString = value;
            }
        }

        private int aValue;
        public int AValue
        {
            get
            {
                return aValue;
            }
            set
            {
                aValue = value;
            }
        }

        public MyAClass() { }
    }

    public class MyBClass
    {
        private MyAClass aClass;
        public MyAClass AClass
        {
            get
            {
                return aClass;
            }
            set
            {
                aClass = value;
            }
        }

        private string bClassName;
        public string BClassName
        {
            get
            {
                return bClassName;
            }
            set
            {
                bClassName = value;
            }
        }
        public MyBClass() { }
    }
}

我认为发生的情况是代码在尝试处理 IsNullOrEmpty 之前处理 ex.InnerException.Message。由于 ex.InnerException 为 null,因此我们在尝试访问 ex.InnerException.Message 时遇到异常。

但我想知道,我需要完整的检查吗? ex.InnerException != null 就足够了吗?如果我们有一个内部异常,我们总是会有一条与之相关的消息吗?

谢谢。

First off, I think I know what's going on, but I thought I'd bring this issue up here for some discussion and see if anyone has an "answer" to this other than what I'm thinking. Because, it doesn't completely make sense to me.

What I found is that when creating a error log for exceptions, I was doing this and it wasn't working:

catch( Exception ex )
{
   LogException( ex.Message );
   if ( !string.IsNullOrEmpty( ex.InnerException.Message ) )
   {
      LogInnerException( ex.InnerException.Message );
   }
}

and lo and behold, when I ran this I'd often get a NullReferenceException. Huh?

I'm checking for null, right?

now, I have to use this:

   if ( ex.InnerException != null && !string.IsNullOrEmpty( ex.InnerException.Message ) 

but that seems counter-intuitive and also counter productive. Because, heck, if I do this:

   if ( !string.IsNullOrEmpty( null ) )

That doesn't give me any problems at all. And if ex.InnerException is null, then certainly ex.InnerException.Message is null, right?

Apparently not.

I wrote a complete console app that reproduces this. If you

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace stringisnullorempty
{
    class Program
    {
        static void Main( string[] args )
        {
            if ( !string.IsNullOrEmpty( null ) )
            {
                Console.WriteLine( "Ha ha ha, right...." );
            }

            MyBClass bClass = new MyBClass();
            bClass.BClassName = "Some B Class Name";
            if ( !string.IsNullOrEmpty( bClass.AClass.AString ) ) //<== Exception occurs here.
            {
                Console.WriteLine( bClass.AClass.AString );
            }
        }
    }

    public class MyAClass
    {
        private string aString;
        public string AString
        {
            get
            {
                return aString;
            }
            set
            {
                aString = value;
            }
        }

        private int aValue;
        public int AValue
        {
            get
            {
                return aValue;
            }
            set
            {
                aValue = value;
            }
        }

        public MyAClass() { }
    }

    public class MyBClass
    {
        private MyAClass aClass;
        public MyAClass AClass
        {
            get
            {
                return aClass;
            }
            set
            {
                aClass = value;
            }
        }

        private string bClassName;
        public string BClassName
        {
            get
            {
                return bClassName;
            }
            set
            {
                bClassName = value;
            }
        }
        public MyBClass() { }
    }
}

What I think is happening is that the code processes ex.InnerException.Message before trying to process the IsNullOrEmpty. Since ex.InnerException is null, we get an exception trying to access ex.InnerException.Message.

I'm wondering though, do I need the full check? Will the ex.InnerException != null be enough. If we have an inner exception, will we always have a message associated with it?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(4

无可置疑 2024-10-28 07:18:08

当您调用 ex.InnerException.Message 时,不是消息为 null,而是 InnerException 对象。

可以这样想:

string temp = ex.InnerException.Message
              //               ^ the error is on this dot.
if (string.IsNullOrEmpty(temp))
{
    ...
}

要完全匹配你想要做的事情,只需使用这个:

catch (Exception ex)  // PLEASE catch something more specific.
{
   LogException(ex.Message);
   if (ex.InnerException != null)
   {
      LogInnerException(ex.InnerException.Message);
   }
}

为了解决这个问题,我过去使用过这个方法:

public Exception GetInnermost(Exception ex)
{
    while (ex.InnerException != null) ex = ex.InnerException;
    return ex;
}


ex.GetBaseException()

When you call ex.InnerException.Message, it's not the message that is null, but rather then InnerException object.

Think of it this way:

string temp = ex.InnerException.Message
              //               ^ the error is on this dot.
if (string.IsNullOrEmpty(temp))
{
    ...
}

To match exactly what you want to do, just use this:

catch (Exception ex)  // PLEASE catch something more specific.
{
   LogException(ex.Message);
   if (ex.InnerException != null)
   {
      LogInnerException(ex.InnerException.Message);
   }
}

In order to solve this problem, I have used this method in the past:

public Exception GetInnermost(Exception ex)
{
    while (ex.InnerException != null) ex = ex.InnerException;
    return ex;
}

ex.GetBaseException()
情绪失控 2024-10-28 07:18:08

如果 InnerException 为 null,则您无法访问其属性之一(在您的情况下为 Message)。这就是为什么你会得到异常,而且不可能有其他情况。

尝试这样思考:string.IsNullOrEmpty 如何知道您用来向其传递参数的表达式?对于函数来说,它只是一个参数。

这两种形式是等效的,但也许第二种形式对您来说会更清楚:

string.IsNullOrEmpty( ex.InnerException.Message ); // exception here

string test = ex.InnerException.Message; // exception HERE
string.IsNullOrEmpty(test);

希望这是清楚的:)

If InnerException is null you cannot access one of its properties (Message in your case). This is why you get the exception, and it could not be otherwise.

Try to think like this: how can string.IsNullOrEmpty know the expression you are using to pass it a parameter? For the function, it is just a parameter.

These two forms are equivalent, but maybe the second will be clearer for you:

string.IsNullOrEmpty( ex.InnerException.Message ); // exception here

string test = ex.InnerException.Message; // exception HERE
string.IsNullOrEmpty(test);

Hope this is clear :)

审判长 2024-10-28 07:18:08

请记住,C# 中的执行顺序是在将参数发送到方法方法体(即压入堆栈)之前对参数进行求值。指令string.IsNullOrEmpty(x)将首先计算x

就您而言,示例中的 xex.InnerException.Message。这是从左到右评估的。如果 exex.InnerException 为 null,则抛出 NullReferenceException。

这里有一种解决这个问题的方法,因为你知道 ex 永远不会为 null,它将检查 InnerException 的 Message 属性(如果有),或者检查 Message 的 Message 属性(如果没有 InnerException)

if(string.IsNullOrEmpty((ex.InnerException ?? ex).Message))
{
    // .. do something 
}

:想要首先检查是否存在 InnerException ,可以像这样完成:

if(ex.InnerException != null) { ... }

或者您想使用异常或内部异常消息,如果两者都存在,则优先使用 InnerException,使用这个:

string exceptionMessage = (ex.InnerException ?? ex).Message;

Remember that the order of execution in C# is that parameters are evaluated before they're send through to the method method body (i.e., pushed on the stack). The instruction string.IsNullOrEmpty(x) will first evaluate x.

In your case, x in the example is ex.InnerException.Message. This is evaluated from left to right. If either ex, or ex.InnerException are null, a NullReferenceException is thrown.

Here's a way to work around this, because you know that ex is never null, which will check the Message property of InnerException if there is any, or of Message if there is no InnerException:

if(string.IsNullOrEmpty((ex.InnerException ?? ex).Message))
{
    // .. do something 
}

But you probably just want to check whether there is an InnerException in the first place and that can be done like so:

if(ex.InnerException != null) { ... }

Or you want to use either the exception or the inner exception message, with preference for InnerException if both are there, use this:

string exceptionMessage = (ex.InnerException ?? ex).Message;
帅气称霸 2024-10-28 07:18:08

基本上,任何时候使用 . 都有可能出现空引用异常。这很痛苦,但是,是的,您需要检查 InnerException 是否为 null。

Basically, any time you use a . you've got a chance for a null reference exception. It's a pain, but yeah, you need to check InnerException for null.

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