C# 使用基类型调用的泛型方法
我的情况是这样的:C# 使用基类型调用的泛型方法,c#,.net,C#,.net,我的情况是这样的: public class Foo{} public interface IBar<in TEx> where TEx : Exception { Foo Build(TEx ex); } public class FooFactory{ public Foo Create<TEx>(TEx ex) where TEx : Exception{ // blah } } // this is an e
public class Foo{}
public interface IBar<in TEx>
where TEx : Exception
{
Foo Build(TEx ex);
}
public class FooFactory{
public Foo Create<TEx>(TEx ex) where TEx : Exception{
// blah
}
}
// this is an external class, cannot be changed.
public class ExceptionContext{
public Exception Ex{get; set;}
}
var context = new ExceptionContext(){ Ex = new MyCustomException (); }
var factory = new FooFactory();
var fooInstance = factory.Create(context.Ex);
当我调用FooFactory.Create()
时,传递的异常始终是System.exception
类型,而不是我预期的MyCustomException
有什么建议吗
编辑:
只需给出一点上下文,我正在尝试在Microsoft.AspNetCore.Mvc.Filters.IExceptionFilter的自定义实现的OneException(ExceptionContext上下文)方法中运行特定于异常的代码。考虑将您的
ExceptionContext
类设置为泛型:
public class ExceptionContext<TEx> where TEx : Exception
{
public TEx Ex{get; set;}
}
public class ExceptionContext<TEx>
where TEx : Exception
{
public <TEx> Ex{get; set;}
}
var context = new ExceptionContext<MyCustomException>(){ Ex = new MyCustomException (); }
var factory = new FooFactory();
var fooInstance = factory.Create(context.Ex);
公共类异常上下文,其中TEx:Exception
{
公共TEx Ex{get;set;}
}
这样,将保留最派生的异常类型,而不是最基本的异常类型(在您的示例中是,System.exception
)
当然,当您的异常是System.exception
的一个实例时,此规则的异常是
当我调用foodfactory.Create()
时,传递的异常类型总是System.exception
这是因为ExceptionContext.Ex
的静态类型是Exception
。泛型方法在编译时绑定,它不知道异常的动态运行时类型不同
下一个最佳选择是在编译时使用显式转换指定运行时类型:
var fooInstance = factory.Create((MyCustomException)context.Ex);
这显然假设运行时类型是MyCustomException
。如果不是,您将得到一个无效的强制转换异常
您还可以使用dynamic
将方法解析延迟到运行时:
dynamic fooInstance = factory.Create((dynamic)context.Ex);
这里的风险是,任何使用fooInstance
的东西也会受到动态的影响,因此您不会获得编译时安全性,任何错误(拼写错误的名称、错误的参数类型)在运行时之前都不会被发现
编辑
删除了答案的这一部分,因为例外上下文
不受OPs控制
您还可以将ExceptionContext
设置为通用:
public class ExceptionContext<TEx> where TEx : Exception
{
public TEx Ex{get; set;}
}
public class ExceptionContext<TEx>
where TEx : Exception
{
public <TEx> Ex{get; set;}
}
var context = new ExceptionContext<MyCustomException>(){ Ex = new MyCustomException (); }
var factory = new FooFactory();
var fooInstance = factory.Create(context.Ex);
公共类例外上下文
其中TEx:例外
{
公共Ex{get;set;}
}
var context=new ExceptionContext(){Ex=new MyCustomException();}
var factory=new foodfactory();
var fooInstance=factory.Create(context.Ex);
如果要使用参数推断,请添加构造函数:
public class ExceptionContext<TEx>
where TEx : Exception
{
public ExceptionContext(TEx exception)
{
this.Ex = exception;
{
public <TEx> Ex{get; set;}
}
var context = new ExceptionContext(new MyCustomException());
var factory = new FooFactory();
var fooInstance = factory.Create(context.Ex);
公共类例外上下文
其中TEx:例外
{
公共例外上下文(TEx例外)
{
这个.Ex=例外;
{
公共Ex{get;set;}
}
var context=new ExceptionContext(new MyCustomException());
var factory=new foodfactory();
var fooInstance=factory.Create(context.Ex);
但目前还不清楚这是否适合你的总体计划。
不幸的是,我不能。ExceptionContext实际上是Microsoft在Microsoft.AspNetCore.Mvc.Filters中提供的。我编辑了这个问题只是为了澄清一点。正如你所说,只有当运行时类型为MyCustomException时,它才起作用。如果我想运行此代码,不管异常类型是什么?我的意思是,我不想在编译时知道什么是异常类型,这就是为什么我想使用一个通用接口…按照您的建议使用动态不会解决问题,传递给工厂的静态类型将始终是System.exception:(factory.Create((dynamic)context.Ex);非常有魅力。谢谢!@MizRaeL好极了。我认为让返回类型动态化就足够了,但让输入参数动态化是有意义的。