我有一个简单的通用错误处理程序IErrorHandler<T>
,其中T
是一个例外。我正在使用structuremap来根据Application_Error中引发的异常获取处理程序的具体实现。所以这是我用来获取处理程序的代码。
var exceptionType = ex.GetType();
var handlerType = typeof(IErrorHandler<>).MakeGenericType(exceptionType);
var handler = IoCContainer.GetInstance(handlerType); // this returns an object
此时,Structuremap已返回正确的实现。但是handler是一个对象,所以我不能调用该接口所具有的任何函数。我可以使用反射来找到Handle方法,但这很脆弱。
var handle = handlerType.GetMethod("Handle");
handle.Invoke(handler, new[] {ex});
当通用程序使用的类型仅在运行时已知时,是否有更好的方法来转换开放式泛型?
这是使用反射的缺点。在运行时提供type-parameter时,无法获得编译时类型。所以你总是卡在object
上。您只能转换为通用基础接口派生的非通用基接口。而是在那里定义你的Handle
方法:
interface IErrorHandler
{
void Handle(Exception e);
}
interface IErrorHandler<T> where T: Exception { }
现在你可以使用这个:
var exceptionType = ex.GetType();
var handlerType = typeof(IErrorHandler<>).MakeGenericType(exceptionType);
var handler = (IErrorHandler) IoCContainer.GetInstance(handlerType); /
handler.Handle(ex);
您还可以向通用接口添加通用方法。现在所有类都应该实现该方法,而对非泛型版本的调用应该重定向到通用版本。
class MyClass<T> : IErrorHandler<T> where T: Exception
{
void Handle(Exception e) { this.Handle((T)e); }
void Handle<T>(T e { /* your code here */ }
}
但是,执行此操作不会阻止调用者将实例强制转换为非泛型接口并将任何异常传递给它。这仍然会产生InvalidCastException
。