V článku zde obsahovala třída ExceptionExtensions tuto pomocnou metodu:
private static System.ServiceModel.ExceptionDetail TryGetExceptionDetail(Exception ex)
{
if (!(ex is System.ServiceModel.FaultException))
{
return null;
}
Type exceptionType = ex.GetType();
while (exceptionType != null)
{
if (exceptionType.IsGenericType && exceptionType.GetGenericTypeDefinition() == typeof(System.ServiceModel.FaultException<>))
{
var property = exceptionType.GetProperty("Detail");
return property.GetValue(ex, null) as System.ServiceModel.ExceptionDetail;
}
exceptionType = exceptionType.BaseType;
}
return null;
}
O co zde šlo?
Máme hodnotu, která je přímo nebo je odvozená z typu FaultException<TDetail> pro nějaké libovolné TDetail. Typ TDetail tedy není předem známý. Úkolem je získat hodnotu vlastnosti Detail (která je typu TDetail) definované na FaultException<TDetail>. (V našem případě nás hodnota vlastnosti Detail zajímala pouze pokud je nebo je odvozená z typu ExceptionDetail, ale to už je ta méně podstatná a jednoduchá část.)
Toto je docela hezký příklad na použití reflection pro manipulaci s generickými typy. V uvedeném řešení bych hlavně vypíchnul následující:
- Na začátku provádíme test zda je hodnota ex typu FaultException. Tento test je zde z důvodu optimalizace. Protože typ FaultException<TDetail> dědí z typu FaultException, platí, že pokud nebude ex typu FaultException nemůže být ani typu FaultException<TDetail> pro libovolné TDetail. V takovém případě se do žádné reflexe nemusíme vůbec pouštět (reflexe je obecně pomalá).
- Celé řešení je v cyklu while, kdy se začíná zkoumáním typu ex.GetType() a pak se v případných dalších iteracích zkoumají postupně typy exceptionType.BaseType. Toto je nutné pokud bude ex typu odvozeného z FaultException<TDetail> a ne FaultException<TDetail> přímo.
- V každé iteraci se pak zkoumá zda je exceptionType generický typ a jeho tzv. generic type definice je typu FaultException<>.
- Pokud je toto splněno provede se již pouze vlastní vytažení hodnoty vlastnosti Detail (díky předchozímu testu je zajištěno, že toto neselže).