C # में एक सामान्य अपवाद के सभी प्रकारों को कैसे पकड़ा जाए


22

मैं एक सामान्य अपवाद वर्ग के सभी वेरिएंट को पकड़ना चाहूंगा और मुझे आश्चर्य हो रहा था कि क्या एक से अधिक कैच ब्लॉक के बिना ऐसा करने का कोई तरीका है। उदाहरण के लिए, मेरे पास एक अपवाद वर्ग है:

public class MyException<T> : Exception
{
    public string MyProperty { get; }

    public MyException(T prop) : base(prop.ToString())
    {
        MyProperty = prop?.ToString();
    }
}

और दो व्युत्पन्न वर्ग:

public class MyDerivedStringException : MyException<string>
{
    public MyDerivedStringException(string prop) : base(prop)
    {

    }
}

public class MyDerivedIntException : MyException<int>
{
    public MyDerivedIntException(int prop) : base(prop)
    {

    }
}

वहाँ दोनों को पकड़ने MyDerivedStringExceptionऔर MyDerivedIntExceptionएक ब्लॉक में पकड़ने का एक तरीका है ।

मैंने यह कोशिश की है:

try
{
   ...
}

catch(Exception e) when (e is MyDerivedStringException || e is MyDerivedIntException)
{
}

लेकिन यह बहुत साफ नहीं है और इसका मतलब है कि मेरी पहुंच नहीं है MyProperty

मैं समस्या के एक सामान्य समाधान में दिलचस्पी रखता हूं, लेकिन मेरे मामले में जेनेरिक अपवाद एक तीसरे पक्ष के पुस्तकालय में परिभाषित किया गया है, जो नीचे बताया गया है, समस्या के लिए कुछ अतिरिक्त बाधाओं को जोड़ता है।

जवाबों:


15

बनाओ MyException<T>एक अंतरफलक को लागू करने और इंटरफ़ेस प्रकार से एक अपवाद के लिए जाँच करें।

इंटरफेस:

public interface IMyException
{
    string MyProperty { get; }
}

इंटरफ़ेस को लागू करने वाला सामान्य वर्ग:

public class MyException<T> : Exception, IMyException
{
    public string MyProperty { get; }

    public MyException(T prop)
    {
        MyProperty = prop?.ToString();
    }
}

व्युत्पन्न वर्ग:

public class MyDerivedStringException : MyException<string>
{
    public MyDerivedStringException(string prop) : base(prop)
    {

    }
}

public class MyDerivedIntException : MyException<int>
{
    public MyDerivedIntException(int prop) : base(prop)
    {

    }
}

उपयोग:

try
{
    // ...
}
catch (Exception e) when (e is IMyException)
{
    // ...
}

वही एक बेस क्लास बनाकर किया जा सकता है जो उस बेस क्लास से प्राप्त Exceptionऔर बनाने से विरासत में MyException<T>मिलता है।


3
मुझे यकीन नहीं है कि यह यहाँ एक इंटरफ़ेस के लायक है - बस एक गैर-जेनेरिक आधार वर्ग के बीच Exceptionऔर MyException<T>ठीक होगा।
जॉन स्कीट

इसके अलावा, ओपी के पास अभी भी जेनेरिक संपत्ति (प्रतिबिंब का उपयोग किए बिना) तक पहुंच नहीं है, जो मुझे लगता है कि असली मुद्दा है।
डेविडजी

10

परीक्षण यदि आपका Typeजेनेरिक से लिया गया है:

Type = typeof(something);
t.GetGenericTypeDefinition()==typeof(MyException<>);

लेकिन यह केवल व्युत्पन्न प्रकारों के लिए ही सही है, जैसे MyException<int>या MyException<string>

यदि आपके पास आगे के डेरिवेटिव हैं जैसे MyDerivedStringExceptionआपको परीक्षण करना था:

ex.GetType.BaseType.GetGenericTypeDefinition()==typeof(MyException<>);

तो यह किसी भी मौजूदा जेनेरिक के लिए काम करता है, लेकिन आपको इस परीक्षण के लिए विरासत के स्तर को जानने की जरूरत है, या सभी आधार प्रकारों के माध्यम से लूप।

तो आप ऐसा कर सकते हैं:

catch(Exception ex) when (ex.GetType.BaseType.GetGenericTypeDefinition()==typeof(MyException<>))

3

यह कार्यान्वयन बॉक्स और अनबॉक्स तब होता है यदि T: मान Valuetype है ... लेकिन उपयोग के संबंध में आप बॉक्स / अनबॉक्स में किए गए प्रयास की संख्या के साथ प्रदर्शन प्रभाव को नियंत्रित कर सकते हैं।

public class MyException<T> : MyException
{
    public T Prop => (T)base.Prop;

    public MyException(T prop) : base(prop)
    {

    }
}

public class MyException : Exception
{
    protected object Prop { get; }

    public MyException(object prop)
    {
         Prop = prop;
    }
}

तर्क

try {
     ...
} catch(MyException e) {
    ...
}

यह एक अच्छा जवाब है और मैंने अपवित्र किया है - दुर्भाग्य से यह मेरे विशिष्ट मुद्दे को हल नहीं करता है क्योंकि सामान्य अपवाद एक तीसरे पक्ष के पुस्तकालय में है इसलिए मैं इसे संपादित नहीं कर सकता।
SBFrancies

2

Unfortunatelly, आप के साथ पकड़ नहीं कर सकते

catch(MyException ex) वर्ग, क्योंकि यह एक प्रकार की उम्मीद करता है।

आपका सबसे अच्छा शर्त यह होगा कि आप एक बेस क्लास या इंटरफ़ेस बनाएँ, इसे पकड़ें और वहाँ से टाइप करें।

टाइप करने और ऐसा करने के तरीके के बारे में यहां पहले से ही एक जवाब मौजूद है ।


1

यह कार्यान्वयन टी / सी के संदर्भ से दूर अपवाद प्रकार के लिए हैंडलिंग प्रतिनिधि को सार करता है ... यह थोड़ा बहुत साहसिक हो सकता है, लेकिन इसके बारे में अच्छा हिस्सा यह है कि आप पुन: उपयोग और संदर्भ के दायरे के आधार पर अलग-अलग हैंडलर इंजेक्ट कर सकते हैं। उपयोग।

public interface IExceptionHandler
{
    object Handle(Exception ex);

    void RegisterExceptionTypeHandler<T>(Func<T,object> handlerDelegate) where T : Exception;
}

पंजीकरण तर्क

handler.RegisterExceptionTypeHandler<MyException<int>>(ex => ...);
handler.RegisterExceptionTypeHandler<MyException<string>>(ex => ...);

try {
    ...
}catch(Exception ex)
{
    ...any validation
    return exceptionHandler.Handle(ex)
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.