我是否可以使用或“投射”类的类型(例如,类CustomClass
的类,因此是typeof(CustomClass)
)来执行一种方法,该方法依赖于提供其相应的类CustomClass
作为“参数”?
Method<CustomClass>();
仅知道
typeof(CustomClass)
如何实现?详细问题:
我正在ASP.NET 4.5中开发Web API。对于Startup的IAppBuilder应用程序,我可以访问无法更改的扩展方法:
public static class AppExtensions
{
public static void AddExceptionTranslation<TException>(
this IAppBuilder app,
HttpStatusCode statusCode,
Func<TException, ApiErrors> messageGenerator))
where TException : Exception;
}
此扩展方法用于将扩展了
Exception
的自定义异常转换为其相应的状态代码。我正在如下使用它:public static void SetUpExceptionHandling(IAppBuilder app)
{
app.AddExceptionTranslation<CustomException>(HttpStatusCode.BadRequest, e => e.ToApiErrors());
app.AddExceptionTranslation<CustomUnauthException>(HttpStatusCode.Forbidden, e => e.ToApiErrors());
// ...
}
现在,我必须为每个自定义异常手动添加一个条目,并在每种情况下提供
TException
。我已经在维护一个数据结构,其中包含每个自定义异常类的typeof
以及其相应的状态代码,唯一ID和我只想在一个地方维护的其他属性。我想使用这个现有的数据结构来遍历它,并对每个自定义异常执行
AddExceptionTranslation<TException>
,我知道它们的Type
。这可能吗?如果不是,我的结构化数据是否可能包含其他内容?当然,我可以咬一口苦瓜,将每个新的自定义异常添加到数据结构中,并手动添加一个用于方法执行的条目,但我真的很想使后者自动化。
请让我知道是否可以澄清。谢谢!
编辑
AddExceptionTranslation实际上接受第二个参数,即lambda表达式,该参数应用于自定义异常:
app.AddExceptionTranslation<CustomException>(HttpStatusCode.Forbidden, e => e.ToApiErrors());
我认为这与该问题无关,但是由于它干扰了建议的解决方案/重复项,因此我感到很酸。我还能以某种方式调用该方法吗?
最佳答案
您需要为集合中的每种类型创建通用方法。这是针对一种类型的方法。下面的代码是人为设计的,但是显示了如何处理lambda。
var exceptionType = typeof(CustomException);
Func<CustomException, ApiErrors> func = e => e.ToApiErrors();
typeof(Extensions)
.GetMethod(nameof(Extensions.AddException))
.MakeGenericMethod(exceptionType)
.Invoke(null, new object[] { builder, HttpStatusCode.Accepted, func });
这是做什么的:
从包含
Extensions
方法的AddExceptionTranslation
类中我们get that method,这是通用的,然后
指定的异常类型可调用的make a version of that
然后是call that method,因为它是静态的,所以我们为对象类型传递
null
除了一个问题,这可以解决您的问题。对于在调用
Func
之前提取的Invoke
的每个异常,您仍然必须“硬编码”异常类型。要解决此问题,请更换Func<CustomException, ApiErrors> func = e => e.ToApiErrors();
与
var funcType = typeof(Func<,>).MakeGenericType(exceptionType, typeof(ApiErrors));
var errorsMethod = typeof(ApiErrorsExtension).GetMethod(nameof(ApiErrorsExtension.ToApiErrors));
var func = Delegate.CreateDelegate(funcType, errorsMethod);
哪一个
创建
Func<,>
的可用版本获取您真正尝试调用的
ToApiErrors()
方法,创建一个可以传递给
AddExceptionTranslation
方法的委托因为这使用反射,所以它很慢。因为您是在启动时这样做的,所以没关系。如果可以的话,有一些库可以缓存反射并发出更快的IL代码以加快反射速度,但是同样,我也不必担心。
您可以做的是将上述代码打包成自己的方法,然后对集合中的每种类型进行调用。