【问题标题】:C# Covariance in generic types泛型类型中的 C# 协方差
【发布时间】:2020-06-15 08:37:34
【问题描述】:

对于这个简单的示例,我无法绕过 C# 协方差,这是我定义模型的方式:

interface IResponse { }
interface ICommand<out TResponse> where TResponse : IResponse { }
class Response : IResponse { }
class Command<TResponse> : ICommand<TResponse> where TResponse : IResponse { }

所以我可以这样使用它

IResponse rsp = new Response(); //Works, obviously!
ICommand<IResponse> cmdi = new Command<Response>(); //Works, but I don't need this 
Command<IResponse> cmd = new Command<Response>(); //Compile time error! :(

Command&lt;TResponse&gt; 中的Command 甚至没有TResponse 类型的任何属性或方法。如何更改它才能正常工作?

【问题讨论】:

  • 类总是不变的。只有接口可以变体。为什么不需要ICommand&lt;IResponse&gt; cmdi = new Command&lt;Response&gt;();?您需要Command 提供的哪些独家产品,而您无法从ICommand 获得?
  • 我需要持久化命令,它们本质上是 POCO 类,如果我想查询具有 List&lt;ICommand&lt;IResponse&gt;&gt; 类型属性的任何内容,Odata core 就会中断

标签: c# generics covariance contravariance mediatr


【解决方案1】:

您的编译时问题出现了,因为您声明了 Command 以便它只能接收 TResponse,而不是 IResponse。

考虑改进你的代码,而不是

class Command<TResponse>

使用

class Command<IResponse>. 

Command 现在可以与任何实现 IResponse 的 TResponseXYZ 类型一起使用,就像您想要的那样。为确保 Command 方法可以访问 TResponseXYZ 类型的所有相关属性,您应该将它们发布为 TResponseXYZ 中的公共属性,并使用 IResponse 接口将它们声明为 get;set;特性。示例:

interface ICommand<out TResponse> where TResponse : IResponse { }

public interface IResponse
{
    int MyField { get; set; }
}

public class TResponseA : IResponse
{
    public int MyField { get; set; }
}

public class TResponseB : IResponse
{
    public int MyField { get; set; }
}

public class Command<TResponse> : ICommand<TResponse> where TResponse : IResponse
{
    public Command(IResponse R)
    {
        // here you can access R.MyField=17 using R.MyField
    }

    public static void Test()
    {
        var rA = new TResponseA() { MyField = 17 };
        var cmdA = new Command<TResponseA>(rA);

        var rB = new TResponseB() { MyField = 17 };
        var cmdB = new Command<TResponseB>(rB);
    }
}

【讨论】:

  • 非常感谢您为帮助我而付出的努力1.命令甚至没有TResponse的任何属性或方法:不需要,TResponse是消费者使用的当将命令传递给 event bus 时,2. class Command&lt;IResponse&gt; 只是不会因为我在第 1 项中提到的原因,3. 你发送的最后一段代码也会引发编译时错误
  • 我已更改我的代码示例,以按原样包含您的声明。要么我不能重现你的编译错误..或者你的问题对我来说变得不清楚。也许其他答案会随之而来。成功解决您的问题..
  • 伙计!感谢您竭诚为我提供帮助,我认为您还没有完全理解我的问题,将 Command&lt;IResponse&gt; 更改为 var 只会解决编译时错误,并且无助于解决需要 Command&lt;IResponse&gt; cmd = new Command&lt;Response&gt;(); 的问题跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-28
  • 1970-01-01
  • 2012-09-29
  • 1970-01-01
相关资源
最近更新 更多