c# - 使用协方差和多个泛型参数时转换为基接口(interface)

标签 c#

我试图让所有这些映射器类都有一个共同的基础:

// base
class BaseInput { public string BaseInputValue { get; set; } }
class BaseOutput { public string BaseOutputValue { get; set; } }

interface IMapper<InputType, out OutputType>
    where InputType : BaseInput
    where OutputType : BaseOutput
{
    OutputType Map(InputType input);
}

// example implementation
class Input : BaseInput { public string InputValue { get; set; } }
class Output : BaseOutput { public string OutputValue { get; set; } }

class MyMapper : IMapper<Input, Output>
{
    public Output Map(Input input)
    {
        // custom mapping done here to Output
        return new Output { /* mapping */ };
    }
}

此代码用于创建一个新的映射器并将其分配给基础编译良好:

var myBaseMapper = (IMapper<BaseInput, BaseOutput>) new MyMapper();

但是我收到运行时错误:

Unable to cast object of type 'MyMapper' to type 'IMapper`2[UserQuery+BaseInput,UserQuery+BaseOutput]'.

如果我减少IMapperIMapper<out OutputType>它工作正常,但这需要在 MyMapper.Map 中进行强制转换,这在每个映射器类中都必须执行,这有点烦人。此外,这让我失去了决定使用哪个映射器来做什么的信息BaseInput所以我必须在其他地方定义它。

在 C# 中这样做是不可能的还是有办法做类似的事情?如果没有,我将不得不重新考虑我的设计。

最佳答案

你不能这样做,因为它没有意义,你的界面在 InputType 中是逆变的。参数(或者更确切地说,如果您将 in 关键字添加到该参数,则会出现这种情况)。要了解为什么这没有意义,让我们看一下您的示例:

您想要实现 IMapper<Input, Output>可分配给IMapper<BaseInput, BaseOutput> 。假设我们创建了一些新的子类 BaseInput ,我们将其称为 MoreInput :

class MoreInput : BaseInput
{
    public string LotsOfInput { get; set; }
}

好吧,现在假设我们有一个方法,其主体看起来像这样(并且您想要的实际上有效):

IMapper<BaseInput, BaseOutput> mapper = new MyMapper();
mapper.Map( new MoreInput() );

嗯,此时没有任何问题:IMapper<BaseInput, BaseOutput>有一个Map接受 BaseInput 的方法作为其参数和 MoreInput BaseInput ,所以我们调用 Map有效。

但事实并非如此,因为 Map我们真正调用的方法需要 Input作为其参数和 MoreInput不是Input 。我们已经破坏了类型系统。

这就是编译器在不允许您隐式进行赋值时告诉您的信息:转换不安全。编译器无法保证您期望的类型就是您获得的类型。

关于c# - 使用协方差和多个泛型参数时转换为基接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33243300/

相关文章:

c# - 静态变量和静态字段的实现区别是什么?

带小数位的 C# 计算

c# - 如何在 Windows Phone 上压缩图像

c# - 使用文本框上的 OnChange 事件进行简单显示

c# - 当 C# 和 mysql 出现问题时,我的事务没有回滚?

c# - 连接两个 Windows 运行时缓冲区的最佳方法是什么?

c# - 是否存在具有 user32.dll 中的函数、类型和常量的预先存在的 .NET 程序集或 NuGet 程序包(或类似程序包)?

c# - 从内存中卸载 DLL

c# - 签名 XML 在 api 门上返回无效签名和错误的签名检查

C# 阻止非托管代码的线程