簡體   English   中英

你能捕捉到異常嗎 <T> T是什么類型?

[英]Can you catch a Exception<T> Where T is any type?

我希望能夠捕獲最具體的WebFaultException<string> ,然后WebFaultException<T> (T是任何其他類型)作為更一般的情況來處理。 這可能嗎?

try
{
    // throw exception
}
catch (WebFaultException<string> e)
{
    // handle more specific type
}
catch (WebFaultException<T> e)
{
    // handle more general type
}
catch (Exception e)
{
}

如其他答案所述; 您不能直接指定捕獲每個WebFaultException<T>而無需知道指定的類型參數,或者捕獲其基本類型。

但是,如果您想捕獲所有 WebFaultException事件並根據泛型是什么來不同地處理響應,則可以簡單地捕獲基本類型,並使用反射使用Type.GetGenericArguments()確定泛型參數的類型。 這是一個簡單的catch子句,以顯示您如何執行此操作:

// ...

catch (FaultException ex)
{
    Type exceptionType = ex.GetType();

    if (exceptionType.IsGenericType)
    {
        // Find the type of the generic parameter
        Type genericType = ex.GetType().GetGenericArguments().FirstOrDefault();

        if (genericType != null)
        {
            // TODO: Handle the generic type.
        }
    }
}

如果您需要更深入的示例,我已經上載了一個測試程序來向PasteBin進行演示。 隨意看看!

不幸的是,這是不可能的。 您可以使用WebFaultException的通用非WebFaultException基類,然后捕獲該異常並使用該處理程序中的反射來處理或拋出更特定的異常。

我建議在異常處理中不要依賴泛型類型參數。 每當您必須基於類型做出決策時,泛型總是會妨礙您。

我從沒想過像這樣的事情,所以我很好奇並做了一些便簽本的實現。 首先,以下工作:

public class WebFaultException : Exception
{
    public WebFaultException() { }
    public WebFaultException(string message) : base(message) { }
    public WebFaultException(string message, Exception innerException) : base(message, innerException) { }
    protected WebFaultException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}

public class WebFaultException<T> : WebFaultException
{
    public WebFaultException() { }
    public WebFaultException(string message) : base(message) { }
    public WebFaultException(string message, Exception innerException) : base(message, innerException) {  }
    protected WebFaultException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) {}
}

作為您的異常定義,然后這些測試都通過:

    [TestMethod]
    public void SpecificGeneric()
    {
        bool hitException = false;
        try
        {
            throw new WebFaultException<string>();
        }
        catch(WebFaultException<string> e)
        {
            hitException = true;
        }

        Assert.IsTrue(hitException);
    }

    [TestMethod]
    public void AnyGeneric()
    {
        bool hitException = false;
        try
        {
            throw new WebFaultException<int>();
        }
        catch (WebFaultException<string> e)
        {
            hitException = false;
        }
        catch (WebFaultException e)
        {
            hitException = true;
        }

        Assert.IsTrue(hitException);
    }

就您想做的事情而言,有一個陷阱。 在提供的代碼中, WebDefaultException<T>是沒有意義的,因為您沒有提供T。但是,您可以這樣解決(有點尷尬)(另一個通過單元測試):

    [TestMethod]
    public void CallingGenericMethod()
    {
        Assert.IsTrue(GenericExceptionMethod<int>());
    }

    private bool GenericExceptionMethod<T>()
    {
        bool hitException = false;
        try
        {
            throw new WebFaultException<int>();
        }
        catch (WebFaultException<string> e)
        {
            hitException = false;
        }
        catch (WebFaultException<T> e)
        {
            hitException = true;
        }
        return hitException;
    }

也就是說,如果處理異常的方法(或類)具有通用參數,則實際上可以捕獲WebFaultException<T> 但是,我要提個警告,這是一件很奇怪的事情-作為您方法的客戶,我被迫傳入一種我將不在意的類型,它是一種內部方法為您提供一些實施異常的詳細信息。

所以,我會說是可能的。 但充其量也很尷尬,也許是不明智的選擇。

尚未提及的幾點:

  1. 如果可以捕獲接口,則`Catch IFooException`語句可能會捕獲`IFooException`,但是由於只能捕獲從Exception派生的類類型,並且由於類類型不支持協方差,因此如何可以將繼承與泛型異常一起使用。 最接近的一種可能是使“ FooException”從“ FooException”派生。 那可能不是一個壞主意,但會有些笨拙。
  2. 如果一個人捕獲了“ SomeException Ex”並將“ Ex”傳遞給了工廠方法“ MakeGenericException(T Ex)”,其中T:Exception`應該產生“ FooException”的實例,那么產生的異常將始終是“ FooException”類型即使捕獲的異常實際上是SomeException的派生類。 鑒於缺少協變的泛型異常類型,這可能是一件好事(因為無法通過期望捕獲“ FooException”的代碼來捕獲“ FooException”),但仍然值得注意。

在異常中使用泛型類型參數似乎是一種不錯的能力,特別是考慮到一組構造函數可以用於整個異常家族。 不幸的是,它似乎無法像人們希望的那樣工作。

泛型類型本身就是一種類型,在運行時沒有模板化參數的概念,因此WebFaultException與WebFaultException沒有任何關系。

如果您是我,我將創建一個非通用的WebFaultException基礎,並從中派生您的通用類型。

您可以通過從通用庫派生異常類來管理類似的事情

public class WebFaultException<T> : WebFaultException
{
    public WebFaultException(T content) : base(content)
    public T Content { get { return ObjContent; } }
}

public class WebFaultException
{
    public WebFaultException(object content)
    {
        ObjContent = content;
    }

    public object ObjContent { get; private set; }
}

現在您可以捕獲WebFaultExceptionWebFaultException<string>

我個人將異常的創建抽象為從Exception派生的泛型類。

https://net7mma.codeplex.com/SourceControl/latest#Common/Exception.cs

我還定義了一個接口IExceptionEx以適應派生。

這使您有機會像這樣包裝異常。

try{ /*error prone logic*/ } catch (Exception ex) { Common.ExceptionExtensions.CreateAndRaiseException(this, "Could not resolve host from the given location. See InnerException.", ex); }

捕獲特定類型然后像這樣...

catch (Common.Exception<RtspClient>) { throw; } catch (Common.Exception<SessionDescription>) { Common.ExceptionExtensions.CreateAndRaiseException(this, "Unable to describe media, Session Description Exception Occured."); }

您可以捕獲所有派生與此:

catch (Common.Exception common) {}

或與此有關的每個異常

catch (Exception ex) {}

使用非通用基類。 無論如何,擁有非通用的基礎通常是一個好習慣。 您也可以將所有非通用數據和功能推入其中,解決了具有各種通用類型的列表的問題。

而不是(適用於是否從Exception繼承):

sealed class MyClass<T> {
   public T GenericProperty { get; set; }
   public int NonGenericProperty { get; set; }
}

做這個:

// optionally abstract
class MyClass {
   public int NonGenericProperty { get; set; } 
}

sealed class MyClass<T> : MyClass {
   public T GenericProperty { get; set; }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM