วิธีจับตัวแปรทั้งหมดของข้อยกเว้นทั่วไปใน C #


22

ฉันต้องการที่จะตรวจจับตัวแปรทั้งหมดของคลาสข้อยกเว้นทั่วไปและฉันสงสัยว่ามีวิธีที่จะทำโดยไม่มีบล็อก catch ที่หลากหลายหรือไม่ ตัวอย่างเช่นฉันมีคลาสยกเว้น:

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>จะใช้ได้
Jon Skeet

นอกจากนี้ OP ยังไม่สามารถเข้าถึงคุณสมบัติทั่วไป (โดยไม่ใช้การสะท้อน) ซึ่งฉันคิดว่าเป็นปัญหาจริง
DavidG

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: Value คือ Valuetype ... แต่สำหรับการใช้งานคุณสามารถควบคุมผลกระทบด้านประสิทธิภาพด้วยจำนวนครั้งที่คุณพยายามทำ box / unbox

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

นี่เป็นคำตอบที่ดีและฉัน upvoted แต่น่าเสียดายที่มันไม่ได้แก้ปัญหาเฉพาะของฉันเนื่องจากข้อยกเว้นทั่วไปอยู่ในห้องสมุดบุคคลที่สามดังนั้นฉันไม่สามารถแก้ไขได้
SBFrancies

2

น่าเสียดายที่คุณไม่สามารถไปกับ

catch(MyException ex) ชั้นเรียนตามที่คาดว่าจะเป็นประเภท

ทางออกที่ดีที่สุดของคุณคือการสร้างคลาสพื้นฐานหรืออินเทอร์เฟซจับมันและรับประเภทจากที่นั่น

มีคำตอบอยู่ที่นี่แล้วเกี่ยวกับวิธีรับชนิดและทำสิ่งนี้


1

การใช้งานนี้เป็นนามธรรมตัวแทนการจัดการสำหรับประเภทข้อยกเว้นออกไปจากบริบทของ T / C ... นี่อาจจะเป็นการผจญภัยเล็ก ๆ น้อย ๆ แต่ส่วนที่ดีเกี่ยวกับมันคือคุณสามารถฉีดตัวจัดการที่แตกต่างกันขึ้นอยู่กับขอบเขตของการใช้ซ้ำและบริบทของ การใช้ประโยชน์

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)
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.