Tam InnerException'ı görüntülemenin doğru yolu nedir?


155

Tam göstermemi göstermenin doğru yolu nedir InnerException.

Bazı InnerExceptions başka bir tane olduğunu buldum InnerExceptionve bu oldukça derin.

Will InnerException.ToString()benim için bir iş yapmak ya da ben döngü gerekiyor InnerExceptionsve yukarı bir inşa Stringile StringBuilder?


Neden iç istisnayı göstermeniz gerekiyor ??
Akram Shahda

26
@Akram çünkü çoğu zaman ilginç olan iç istisnadır. Bir örnek, bir şeyler ters gittiğinde sadece InvalidOperationException özel durumunu atan XmlSerializer'dır. Yanlış giden şey iç istisnadır.
adrianm

4
@AkramShahda Peki, belki de bu yöntemi günlük kaydınızda kullanmak istersiniz?
cederlof

Yanıtlar:


239

Yalnızca yazdırabilirsiniz exception.ToString()- bu, tüm iç içe yerleştirilmiş InnerExceptions için tam metni de içerecektir .


18
Bu, sadece istisna mesajı ve iç istisna mesajlarını değil, başka bir saçmalık yükünü de içerir
ᴍᴀᴛᴛ ʙᴀᴋᴇʀ

sadece özlü olmak için aslında .ToString () öğesine ihtiyacınız yoktur, sadece istisna kullanmak aynı şeyi yapar.
Alex Stephens

3
@AlexStephens haklısınız, ancak yalnızca bir dizeden önce "dize" için örtük bir dökümünüz varsa, "dize" + istisna
oo_dev

1
Bilginize: Bu özel bir çağrı olmaz ToStringayrıntılı olarak iç istisnalar için yöntemler iç istisnalar için çağrı sanal ToString System.Exception.ToString gelmez Why? .
Jeff B

45

Sadece kullan exception.ToString()

http://msdn.microsoft.com/en-us/library/system.exception.tostring.aspx

ToString'in varsayılan uygulaması geçerli istisnayı atan sınıfın adını, iletiyi, iç istisnada ToString çağrısının sonucunu ve Environment.StackTrace çağrılmasının sonucunu alır. Bu üyelerden herhangi biri boşsa, değeri döndürülen dizeye dahil edilmez.

Hata mesajı yoksa veya boş bir dize ("") ise, hata mesajı döndürülmez. İç kural dışı durumun adı ve yığın izlemesi yalnızca boş değilse döndürülür.

exception.ToString () ayrıca bu istisnanın iç istisnası için .ToString () öğesini çağırır ve bu şekilde devam eder ...


45

Genellikle gürültünün çoğunu kaldırmak için bunu yapıyorum:

void LogException(Exception error) {
    Exception realerror = error;
    while (realerror.InnerException != null)
        realerror = realerror.InnerException;

    Console.WriteLine(realerror.ToString())
}    

Edit: Bu cevabı unuttum ve kimse sadece yapabileceğinizi işaret şaşırdı

void LogException(Exception error) {
    Console.WriteLine(error.GetBaseException().ToString())
}    

Bu yöntem, en derin iç istisna dışında her şeyi gizler. Bu "Sıfıra böl" hatası gibi sıradan bir şey olsaydı, nerede oluştuğu ve neye yol açtığı belirsiz olurdu. Açıkçası, tam bir yığın izi genellikle dağınık bir aşırılıktır, ancak sadece iç istisnayı okumak diğer uçtur. user3016982'nin cevabı çok daha iyi. Her istisna mesajını kötü iz bırakmadan yığındaki alırsınız.
JamesHoux

1
@JamesHoux Hangisi "user3016982" yanıtıdır? Onu burada bulamıyorum.
maracuja-juice

Kullanıcı 3016982 ThomazMoura'dır, bakınız: stackoverflow.com/users/3016982/thomazmoura
Apfelkuacha

@JamesHoux, iç kural dışı durum, hatanın nerede oluştuğunu ve neye yol açtığını gösteren tam bir yığın izine sahiptir. Kaldırılan yığın izlerinden hangi ek bilgileri aldığınızı anlamayın. İstisna mesajları başka bir şeydir ve hepsini toplamak yararlı olabilir.
adrianm

2
Neden sadece kullanmıyorsun error.GetBaseException()? Ben de aynı şeyi düşünüyorum ...
Robba

37

@ Jon'un cevabı, tüm ayrıntıları (tüm mesajlar ve yığın izleme) ve önerileni istediğinizde en iyi çözümdür.

Ancak, yalnızca iç mesajları istediğiniz durumlar olabilir ve bu durumlar için aşağıdaki uzantı yöntemini kullanıyorum:

public static class ExceptionExtensions
{
    public static string GetFullMessage(this Exception ex)
    {
        return ex.InnerException == null 
             ? ex.Message 
             : ex.Message + " --> " + ex.InnerException.GetFullMessage();
    }
}

Bu yöntemi, izleme ve günlük kaydı için farklı dinleyicilerim olduğunda ve bunlar üzerinde farklı görüşlere sahip olmak istediğimde kullanırım. Bu şekilde .ToString()yöntemi kullanarak hata ayıklama için dev ekibine e-posta ile yığın izleme ile tüm hata gönderen bir dinleyici ve yığın izleme olmadan her gün meydana gelen tüm hataların geçmişi ile dosyaya bir günlük yazan bir dinleyici olabilir .GetFullMessage()yöntemi.


7
FYI A ise ex, AggregateExceptionbu çıktıya hiçbir iç istisna dahil edilmez
kornman00

3
Bu bir stok .NET yöntemi olmalıdır. Herkes bunu kullanıyor olmalı.
JamesHoux

9

MessageDerin istisnaların sadece bir kısmını yazdırmak için şöyle bir şey yapabilirsiniz:

public static string ToFormattedString(this Exception exception)
{
    IEnumerable<string> messages = exception
        .GetAllExceptions()
        .Where(e => !String.IsNullOrWhiteSpace(e.Message))
        .Select(e => e.Message.Trim());
    string flattened = String.Join(Environment.NewLine, messages); // <-- the separator here
    return flattened;
}

public static IEnumerable<Exception> GetAllExceptions(this Exception exception)
{
    yield return exception;

    if (exception is AggregateException aggrEx)
    {
        foreach (Exception innerEx in aggrEx.InnerExceptions.SelectMany(e => e.GetAllExceptions()))
        {
            yield return innerEx;
        }
    }
    else if (exception.InnerException != null)
    {
        foreach (Exception innerEx in exception.InnerException.GetAllExceptions())
        {
            yield return innerEx;
        }
    }
}

Bu , satır sonu ile sınırlandırılmış olan AggregateExceptiontüm Messagemülkleri yazdırmak için tüm iç istisnaları (durumlar dahil ) tekrar eder.

Örneğin

var outerAggrEx = new AggregateException(
    "Outer aggr ex occurred.",
    new AggregateException("Inner aggr ex.", new FormatException("Number isn't in correct format.")),
    new IOException("Unauthorized file access.", new SecurityException("Not administrator.")));
Console.WriteLine(outerAggrEx.ToFormattedString());

Dış aggr oluştu.
İç aggr ör.
Sayı doğru biçimde değil.
Yetkisiz dosya erişimi.
Yönetici değil.


Daha fazla ayrıntı için diğer İstisna özelliklerini dinlemeniz gerekir . Örneğin Databazı bilgilere sahip olacak. Şunları yapabilirsiniz:

foreach (DictionaryEntry kvp in exception.Data)

Türetilmiş tüm özellikleri (temel Exceptionsınıfta değil) elde etmek için şunları yapabilirsiniz:

exception
    .GetType()
    .GetProperties()
    .Where(p => p.CanRead)
    .Where(p => p.GetMethod.GetBaseDefinition().DeclaringType != typeof(Exception));

+1, Bu neredeyse benim yaptığımla aynı şey. Diğer benzer türleri işlemek için IEnumerable<Exception>sabit kodlama yerine bir mülk uygulaması aramayı düşünün AggregrateException. Ayrıca hariç tutun p.IsSpecialNameve pi.GetIndexParameters().Length != 0sorunları önlemek için.
Çıktıya

@adrianm emlak bilgisi kontrolleri hakkında iyi bir nokta. İstisnaların toplanmasını kontrol etmekle ilgili olarak, her şey hattı çizmek istediğiniz yerle ilgilidir. Tabii ki de yapılabilir ..
nawfal

4

Yaparım:

namespace System {
  public static class ExtensionMethods {
    public static string FullMessage(this Exception ex) {
      if (ex is AggregateException aex) return aex.InnerExceptions.Aggregate("[ ", (total, next) => $"{total}[{next.FullMessage()}] ") + "]";
      var msg = ex.Message.Replace(", see inner exception.", "").Trim();
      var innerMsg = ex.InnerException?.FullMessage();
      if (innerMsg is object && innerMsg!=msg) msg = $"{msg} [ {innerMsg} ]";
      return msg;
    }
  }
}

Bu, tüm iç istisnaları "güzel yazdırır" ve ayrıca AgregateExceptions ve InnerException.Message'ın Message ile aynı olduğu durumları işler.


3

Tüm istisnalar hakkında bilgi istiyorsanız o zaman kullanın exception.ToString(). Tüm iç istisnalardan veri toplayacaktır.

Sadece orijinal istisnayı istiyorsanız o zaman kullanın exception.GetBaseException().ToString(). Bu size ilk istisna, örneğin en derin iç istisna veya iç istisna yoksa mevcut istisna getirecektir.

Misal:

try {
    Exception ex1 = new Exception( "Original" );
    Exception ex2 = new Exception( "Second", ex1 );
    Exception ex3 = new Exception( "Third", ex2 );
    throw ex3;
} catch( Exception ex ) {
    // ex => ex3
    Exception baseEx = ex.GetBaseException(); // => ex1
}

2

nawfal'ın cevabında birikme.

cevabını kullanırken aggrEx eksik bir değişkeni vardı, ben ekledim.

ExceptionExtenstions.class dosyası:

// example usage:
// try{ ... } catch(Exception e) { MessageBox.Show(e.ToFormattedString()); }

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

namespace YourNamespace
{
    public static class ExceptionExtensions
    {

        public static IEnumerable<Exception> GetAllExceptions(this Exception exception)
        {
            yield return exception;

            if (exception is AggregateException )
            {
                var aggrEx = exception as AggregateException;
                foreach (Exception innerEx in aggrEx.InnerExceptions.SelectMany(e => e.GetAllExceptions()))
                {
                    yield return innerEx;
                }
            }
            else if (exception.InnerException != null)
            {
                foreach (Exception innerEx in exception.InnerException.GetAllExceptions())
                {
                    yield return innerEx;
                }
            }
        }


        public static string ToFormattedString(this Exception exception)
        {
            IEnumerable<string> messages = exception
                .GetAllExceptions()
                .Where(e => !String.IsNullOrWhiteSpace(e.Message))
                .Select(exceptionPart => exceptionPart.Message.Trim() + "\r\n" + (exceptionPart.StackTrace!=null? exceptionPart.StackTrace.Trim():"") );
            string flattened = String.Join("\r\n\r\n", messages); // <-- the separator here
            return flattened;
        }
    }
}

Bir istisna yaşadım çünkü:e.StackTrace == null
Andrei Krasutski

1
Güncelledim .Select (e => e.Message.Trim () + "\ r \ n" + (e.StackTrace! = Null? StackTrace.Trim (): "")); belki bu yardımcı olur
Shimon Doodkin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.