Можете ли вы поймать 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)
{
}
Ответы
Ответ 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
Несколько пунктов, о которых еще не упоминалось:
- Если бы можно было поймать интерфейсы, было бы возможно, чтобы оператор `Catch IFooException` поймал` IFooException`, но поскольку можно только улавливать типы классов, полученные из Exception, и поскольку типы классов не поддерживают ковариацию, существуют пределы того, насколько хорошо можно использовать концепцию наследования с общими исключениями. Самое близкое, что может произойти, - это получить "FooException" от "FooException". Это может быть не плохая идея, но будет немного неуклюже.
- Если кто-то ловит `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) {}