Подтвердить что ты не робот

Можете ли вы поймать Exception <T> Где T - любой тип?

Я хочу уловить 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)
{
}
4b9b3361

Ответ 1

Как упоминались другие ответы; вы не можете напрямую указывать, чтобы поймать каждый 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. Не стесняйтесь смотреть!

Ответ 2

К сожалению, это невозможно. Вы можете использовать обычный базовый класс WebFaultException, а затем поймать его и обработать или реконструировать более определенные исключения, используя отражение в этом обработчике.

Я бы рекомендовал не зависеть от аргументов обобщенного типа при обработке исключений. Дженерики всегда будут мешать вам, когда вам нужно принимать решения на основе типа.

Ответ 3

Я никогда не думал о чем-то подобном, поэтому мне стало любопытно и сделал небольшую замену. Прежде всего, следующие работы:

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. Однако вы можете обойти это (несколько неловко), как это (другое прохождение unit test):

    [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>. Тем не менее, я хотел бы предупредить, что это очень странная вещь - как клиент вашего метода, я вынужден перейти к типу, который будет использоваться для ничего, что меня волнует, и является внутренним детализация для вас за некоторым исключением, которое вы хотите поймать.

Итак, я бы сказал, да, возможно. Но также неловко в лучшем случае и, возможно, не рекомендуется.

Ответ 4

Несколько пунктов, о которых еще не упоминалось:

  1. Если бы можно было поймать интерфейсы, было бы возможно, чтобы оператор `Catch IFooException` поймал` IFooException`, но поскольку можно только улавливать типы классов, полученные из Exception, и поскольку типы классов не поддерживают ковариацию, существуют пределы того, насколько хорошо можно использовать концепцию наследования с общими исключениями. Самое близкое, что может произойти, - это получить "FooException" от "FooException". Это может быть не плохая идея, но будет немного неуклюже.
  2. Если кто-то ловит `SomeException Ex` и передает` Ex` в метод factory `MakeGenericException (T Ex), где T: Exception`, который должен создать экземпляр` FooException`, результирующее исключение всегда будет быть типа `FooException`, даже если пойманное исключение фактически является производным от` SomeException`. Учитывая отсутствие ковариантных генерических типов исключений, это, вероятно, хорошо (поскольку "FooException" не может быть пойманным кодом, ожидающим поймать "FooException" ), но это все еще стоит отметить.

    Использование параметров типового типа с исключениями кажется приятной способностью, особенно учитывая, что один набор конструкторов может использоваться для целого семейства исключений. К сожалению, похоже, что он работает почти так же хорошо, как хотелось бы.

Ответ 5

Типичный тип - это сам по себе тип, во время выполнения не существует понятия параметра templated, поэтому WebFaultException никак не связано с исключением WebFaultException.

Если бы я был вами, я бы создал не общую базу WebFaultException и вывел из нее свои общие типы.

Ответ 6

Вы можете управлять чем-то подобным, вызывая свой класс исключений из общей базы

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; }
}

теперь вы можете поймать WebFaultException или WebFaultException<string>

Ответ 7

Я лично абстрактно создаю исключения для родового класса, который получен из 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) {}