ইনারএক্সসেপশন (গুলি) থেকে সমস্ত বার্তা পাচ্ছেন?


92

ব্যাতিক্রমের ইনারেক্সেপশন (গুলি) এর সমস্ত স্তরে হাঁটার জন্য একটি লিনকিউ স্টাইল "শর্ট হ্যান্ড" কোড লেখার কোনও উপায় আছে কি? আমি এটি কোনও এক্সটেনশন ফাংশন (নীচের হিসাবে) কল করার পরিবর্তে বা Exceptionশ্রেণীর উত্তরাধিকার সূত্রে লিখতে পছন্দ করব ।

static class Extensions
{
    public static string GetaAllMessages(this Exception exp)
    {
        string message = string.Empty;
        Exception innerException = exp;

        do
        {
            message = message + (string.IsNullOrEmpty(innerException.Message) ? string.Empty : innerException.Message);
            innerException = innerException.InnerException;
        }
        while (innerException != null);

        return message;
    }
}; 

4
আমি আপনাকে জিজ্ঞাসা করতে পারি আপনি কেন এক্সটেনশন পদ্ধতিগুলি বাদ দিয়ে অন্য কিছু ব্যবহার করতে চান? আপনার কোডটি আমার কাছে দুর্দান্ত দেখায় এবং আপনার কোডের সর্বত্র পুনরায় ব্যবহারযোগ্য।
— ken2k

@ কেন ২ কে: যদিও আপনি এখনই তার বার্তাটি এইভাবে তৈরি করতে চান না ...
— জেফ মার্কাডো

4
@ জেফমারকাডো হ্যাঁ, তবে "এক্সটেনশন পদ্ধতি" ধারণাটিতে সমস্যা কী?
— কেন 2 কে

@ কেন 2 কে: সত্যি কথা বলতে কী, আমি সত্যিই আপনার প্রশ্নটি বুঝতে পারি না ... আপনি কেবল উল্লেখ করেছেন যে কোডটি ত্রুটিযুক্ত হওয়ার পরে "ভাল দেখায়"।
— জেফ মার্কাডো

4
একটু সচেতন থাকুন AggregateExceptionএর আচরণে কিছুটা আলাদা। InnerExceptionsপরিবর্তে আপনাকে সম্পত্তি দিয়ে যেতে হবে। উভয় কেস কভার করতে এখানে স্ট্যাকওভারফ্লো.com/ a/ 52042708 / 661933 একটি সুবিধাজনক এক্সটেনশন পদ্ধতি সরবরাহ করেছেন।
— নওফাল

উত্তর:


92

দুর্ভাগ্যক্রমে লিনকুই এমন পদ্ধতিগুলি সরবরাহ করে না যা শ্রেণিবদ্ধ কাঠামো প্রক্রিয়া করতে পারে, কেবল সংগ্রহগুলি।

আমার কাছে আসলে কিছু এক্সটেনশন পদ্ধতি রয়েছে যা এটি করতে সহায়তা করতে পারে। আমার হাতে সঠিক কোড নেই তবে এগুলি এরকম কিছু:

// all error checking left out for brevity

// a.k.a., linked list style enumerator
public static IEnumerable<TSource> FromHierarchy<TSource>(
    this TSource source,
    Func<TSource, TSource> nextItem,
    Func<TSource, bool> canContinue)
{
    for (var current = source; canContinue(current); current = nextItem(current))
    {
        yield return current;
    }
}

public static IEnumerable<TSource> FromHierarchy<TSource>(
    this TSource source,
    Func<TSource, TSource> nextItem)
    where TSource : class
{
    return FromHierarchy(source, nextItem, s => s != null);
}

তারপরে এই ক্ষেত্রে ব্যতিক্রমগুলি গণনার জন্য আপনি এটি করতে পারেন:

public static string GetaAllMessages(this Exception exception)
{
    var messages = exception.FromHierarchy(ex => ex.InnerException)
        .Select(ex => ex.Message);
    return String.Join(Environment.NewLine, messages);
}

81

তুমি এরকম কিছু বোঝাতে চাও?

public static class Extensions
{
    public static IEnumerable<Exception> GetInnerExceptions(this Exception ex)
    {
        if (ex == null)
        {
            throw new ArgumentNullException("ex");
        }

        var innerException = ex;
        do
        {
            yield return innerException;
            innerException = innerException.InnerException;
        }
        while (innerException != null);
    }
}

আপনি আপনার সম্পূর্ণ ব্যতিক্রম শ্রেণিবিন্যাসের উপরে এইভাবে লিনকিউ করতে পারেন:

exception.GetInnerExceptions().Where(e => e.Message == "Oops!");

4
প্রস্তাবিত সমাধানের চেয়ে অনেক ক্লিনার
— রাইস

4
@ রাইস দয়া করে নোট করুন যে প্রস্তাবিত সমাধানটি একাধিক সমতলকরণের পরিস্থিতিতে এই সমস্যার একটি সাধারণীকরণ। এটি আরও জটিল হওয়ার বিষয়টি প্রত্যাশিত।
— জুলাইগলন

31

এই কোড সম্পর্কে:

private static string GetExceptionMessages(this Exception e, string msgs = "")
{
  if (e == null) return string.Empty;
  if (msgs == "") msgs = e.Message;
  if (e.InnerException != null)
    msgs += "\r\nInnerException: " + GetExceptionMessages(e.InnerException);
  return msgs;
}

ব্যবহার:

Console.WriteLine(e.GetExceptionMessages())

আউটপুট উদাহরণ:

এই বার্তাটি গ্রহণ করতে পারে এমন কোনও HTTP: //nnn.mmm.kkk.ppp: 8000 / রাউটিংসার্ভিস / রাউটারে কোনও শেষ পয়েন্ট শোনেনি। এটি প্রায়শই কোনও ভুল ঠিকানা বা এসওএপি ক্রিয়া দ্বারা ঘটে থাকে। আরও তথ্যের জন্য অন্তর্ভুক্তিটি উপস্থিত থাকলে দেখুন।

অভ্যন্তরীণ ধারণা: দূরবর্তী সার্ভারে সংযোগ করতে অক্ষম

অভ্যন্তরীণ ধারণা: কোনও সংযোগ তৈরি করা যায়নি কারণ টার্গেট মেশিন সক্রিয়ভাবে এটি অস্বীকার করেছে 127.0.0.1:8000


4
আপনি StringBuilderএখানে সত্যিই ব্যবহার বিবেচনা করা উচিত । NullReferenceExceptionনাল রেফারেন্সের জন্য অনুরোধ করা হলে আইএমও এক্সটেনশন পদ্ধতিটি ছোঁড়া উচিত ।
— dstarkowski

27

আমি জানি এটি সুস্পষ্ট, তবে সম্ভবত সবার জন্য নয়।

exc.ToString();

এটি আপনার সমস্ত অভ্যন্তরীণ ব্যতিক্রমগুলির মধ্য দিয়ে যাবে এবং সমস্ত বার্তা ফেরত পাঠাবে, তবে স্ট্যাক ট্রেস ইত্যাদির সাথে with


4
হ্যাঁ ঠিক আছে যদি টুস্ট্রিংয়ের সাথে ব্ল্যাটেড হয়ে ওঠা সমস্ত স্ট্যাক ট্রেসের সাথে থাকতে আপনার খুশি হয়। এটি প্রায়শই প্রসঙ্গে উপযুক্ত হয় না যেমন মেসেজটি কোনও ব্যবহারকারীর কাছে যাচ্ছে। অন্যদিকে বার্তা অভ্যন্তরীণ ব্যতিক্রম বার্তা দেয় না (টোস্ট্রিংয়ের বিপরীতে যা পুনরাবৃত্তি করে)। আমরা প্রায়শই যা চাই তা হ'ল অ-প্রতিরোধী ফুলম্যাসেজ যা পিতামাতার এবং অভ্যন্তরীণ ব্যতিক্রমগুলির সমস্ত বার্তা।
— রিসিবব

16

আপনার এক্সটেনশন পদ্ধতি বা পুনরাবৃত্তি কলগুলির প্রয়োজন নেই:

try {
  // Code that throws exception
}
catch (Exception e)
{
  var messages = new List<string>();
  do
  {
    messages.Add(e.Message);
    e = e.InnerException;
  }
  while (e != null) ;
  var message = string.Join(" - ", messages);
}

উজ্জ্বল! যদি আমি এটি সম্পর্কে চিন্তা করতাম।
— রাউল মার্কেজ

11

লিনকিউ সাধারণত বস্তুর সংগ্রহের সাথে কাজ করতে ব্যবহৃত হয়। তবে, যুক্তিযুক্তভাবে, আপনার ক্ষেত্রে অবজেক্টগুলির কোনও সংগ্রহ নেই (তবে একটি গ্রাফ)। সুতরাং কিছু লিনকিউ কোড সম্ভব হলেও, আইএমএইচও এটি বরং সংশ্লেষিত বা কৃত্রিম হবে।

অন্যদিকে, আপনার উদাহরণটি মূল উদাহরণের মতো দেখায় যেখানে এক্সটেনশন পদ্ধতিগুলি আসলে যুক্তিসঙ্গত। পুনরায় ব্যবহার, এনক্যাপসুলেশন ইত্যাদির মতো বিষয়ে কথা বলতে হবে না

আমি কোনও এক্সটেনশন পদ্ধতিতে থাকব, যদিও আমি এটি সেভাবে প্রয়োগ করেছিলাম:

public static string GetAllMessages(this Exception ex)
{
   if (ex == null)
     throw new ArgumentNullException("ex");

   StringBuilder sb = new StringBuilder();

   while (ex != null)
   {
      if (!string.IsNullOrEmpty(ex.Message))
      {
         if (sb.Length > 0)
           sb.Append(" ");

         sb.Append(ex.Message);
      }

      ex = ex.InnerException;
   }

   return sb.ToString();
}

তবে এটি মূলত স্বাদের একটি বিষয়।


7

আমার মনে হয় না, ব্যতিক্রম কোনও আইএনওমারেবল নয় তাই আপনি নিজেরাই এর বিরুদ্ধে একটি লিনক কোয়েরি করতে পারবেন না।

অভ্যন্তরীণ ব্যতিক্রমগুলি ফিরিয়ে আনতে একটি এক্সটেনশন পদ্ধতি এটির মতো কাজ করবে

public static class ExceptionExtensions
{
    public static IEnumerable<Exception> InnerExceptions(this Exception exception)
    {
        Exception ex = exception;

        while (ex != null)
        {
            yield return ex;
            ex = ex.InnerException;
        }
    }
}

তারপরে আপনি এই জাতীয় লিঙ্ক কোয়েরি ব্যবহার করে সমস্ত বার্তা যুক্ত করতে পারেন:

var allMessageText = string.Concat(exception.InnerExceptions().Select(e => e.Message + ","));

6

অন্যকে যুক্ত করতে আপনি ব্যবহারকারীকে কীভাবে বার্তাগুলি পৃথক করবেন সে বিষয়ে সিদ্ধান্ত নিতে দিতে পারেন:

    public static string GetAllMessages(this Exception ex, string separator = "\r\nInnerException: ")
    {
        if (ex.InnerException == null)
            return ex.Message;

        return ex.Message + separator + GetAllMessages(ex.InnerException, separator);
    }

6
    public static string GetExceptionMessage(Exception ex)
    {
        if (ex.InnerException == null)
        {
            return string.Concat(ex.Message, System.Environment.NewLine, ex.StackTrace);
        }
        else
        {
            // Retira a última mensagem da pilha que já foi retornada na recursividade anterior
            // (senão a última exceção - que não tem InnerException - vai cair no último else, retornando a mesma mensagem já retornada na passagem anterior)
            if (ex.InnerException.InnerException == null)
                return ex.InnerException.Message;
            else
                return string.Concat(string.Concat(ex.InnerException.Message, System.Environment.NewLine, ex.StackTrace), System.Environment.NewLine, GetExceptionMessage(ex.InnerException));
        }
    }

4

আমি এখানে সর্বাধিক সংক্ষিপ্ত সংস্করণটি ছেড়ে যাচ্ছি:

public static class ExceptionExtensions
{
    public static string GetMessageWithInner(this Exception ex) =>
        string.Join($";{ Environment.NewLine }caused by: ",
            GetInnerExceptions(ex).Select(e => $"'{ e.Message }'"));

    public static IEnumerable<Exception> GetInnerExceptions(this Exception ex)
    {
        while (ex != null)
        {
            yield return ex;
            ex = ex.InnerException;
        }
    }
}

3
public static class ExceptionExtensions
{
    public static IEnumerable<Exception> GetAllExceptions(this Exception ex)
    {
        Exception currentEx = ex;
        yield return currentEx;
        while (currentEx.InnerException != null)
        {
            currentEx = currentEx.InnerException;
            yield return currentEx;
        }
    }

    public static IEnumerable<string> GetAllExceptionAsString(this Exception ex)
    {            
        Exception currentEx = ex;
        yield return currentEx.ToString();
        while (currentEx.InnerException != null)
        {
            currentEx = currentEx.InnerException;
            yield return currentEx.ToString();
        }            
    }

    public static IEnumerable<string> GetAllExceptionMessages(this Exception ex)
    {
        Exception currentEx = ex;
        yield return currentEx.Message;
        while (currentEx.InnerException != null)
        {
            currentEx = currentEx.InnerException;
            yield return currentEx.Message;
        }
    }
}

1

এখানে পূর্বনির্ধারিত বেশিরভাগ সমাধানে নিম্নলিখিত প্রয়োগের ত্রুটি রয়েছে:

  • nullব্যতিক্রমগুলি পরিচালনা করুন
  • এর অভ্যন্তরীণ ব্যতিক্রমগুলি পরিচালনা করুন AggregateException
  • অভ্যন্তরীণ ব্যতিক্রমগুলি পুনরাবৃত্তি করার জন্য সর্বাধিক গভীরতা নির্ধারণ করুন (যেমন: বিজ্ঞপ্তি নির্ভরতা)

একটি ভাল বাস্তবায়ন এটি এখানে:

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

public static string AggregateMessages(this Exception ex) =>
    ex.GetInnerExceptions()
        .Aggregate(
            new StringBuilder(),
            (sb, e) => sb.AppendLine(e.Message),
            sb => sb.ToString());

public static IEnumerable<Exception> GetInnerExceptions(this Exception ex, int maxDepth = 5)
{
    if (ex == null || maxDepth <= 0)
    {
        yield break;
    }

    yield return ex;

    if (ex is AggregateException ax)
    {
        foreach(var i in ax.InnerExceptions.SelectMany(ie => GetInnerExceptions(ie, maxDepth - 1)))
            yield return i;
    }

    foreach (var i in GetInnerExceptions(ex.InnerException, maxDepth - 1))
        yield return i;
}

ব্যবহারের উদাহরণ:

try
{
    // ...
}
catch(Exception e)
{
    Log.Error(e, e.AggregateMessages());
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.