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好极了。我认为让返回类型动态化就足够了,但让输入参数动态化是有意义的。