string.IsNullOrEmpty () не похоже на работу над строкой в ​​классе в классе - PullRequest
2 голосов
/ 11 марта 2011

Прежде всего, я думаю, что я знаю, что происходит, но я подумал, что подниму этот вопрос здесь для некоторого обсуждения и выясню, есть ли у кого-нибудь "ответ" на этот вопрос, кроме того, о чем я думаю. Потому что для меня это не совсем понятно.

Я обнаружил, что при создании журнала ошибок для исключений я делал это, и оно не работало:

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

и вот, когда я запускаю это, я часто получаю исключение NullReferenceException. А?

Я проверяю на ноль, верно?

Теперь я должен использовать это:

   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() { }
    }
}

Я думаю, что происходит то, что код обрабатывает ex.InnerException.Message, прежде чем пытаться обработать IsNullOrEmpty. Поскольку ex.InnerException имеет значение null, мы получаем исключение при попытке доступа к ex.InnerException.Message.

Мне интересно, нужна ли мне полная проверка? Будет ли ex.InnerException! = Null достаточно. Если у нас есть внутреннее исключение, будет ли с ним всегда связано сообщение?

Спасибо.

Ответы [ 4 ]

7 голосов
/ 11 марта 2011

Когда вы вызываете ex.InnerException.Message, это не пустое сообщение, а InnerException object.

Думайте об этом так:

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()
0 голосов
/ 11 марта 2011

По сути, каждый раз, когда вы используете ., у вас есть шанс исключить нулевую ссылку. Это боль, но да, вам нужно проверить InnerException на ноль.

0 голосов
/ 11 марта 2011

Помните, что порядок выполнения в C # заключается в том, что параметры оцениваются до , они отправляются в тело метода метода (т.е. помещаются в стек). Инструкция string.IsNullOrEmpty(x) сначала оценит x.

В вашем случае x в этом примере - ex.InnerException.Message. Это оценивается слева направо. Если либо ex, либо ex.InnerException равны нулю, генерируется исключение NullReferenceException.

Вот способ обойти это, потому что вы знаете, что ex никогда не имеет значение null, что будет проверять свойство Message InnerException, если оно есть, или Message, если нет InnerException:

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

Но вы, вероятно, просто хотите проверить, есть ли InnerException во-первых, и это можно сделать так:

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

Или вы хотите использовать либо исключение, либо внутреннее сообщение об исключении, с предпочтением InnerException, если оба есть, используйте это:

string exceptionMessage = (ex.InnerException ?? ex).Message;
0 голосов
/ 11 марта 2011

Если InnerException равно нулю, вы не можете получить доступ к одному из его свойств (Message в вашем случае).Вот почему вы получаете исключение, а иначе не может быть.

Попробуйте подумать так: как string.IsNullOrEmpty может узнать выражение, которое вы используете для передачи ему параметра?Для функции это просто параметр.

Эти две формы эквивалентны, но, возможно, вторая будет более понятной для вас:

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

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

Надеюсь, это понятно :)

...