在泛型中具有协方差的强制转换类

问题描述 投票:0回答:1

我对泛型和 C# 中的不变性和协变性有疑问

我想要cast handlerConcrete,这里是代码

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        var handlerConcrete = new HandlerTestConcrete<MessageBaseTestConcrete, ResponseMessageBaseTestConcrete>() { };
        var cast = handlerConcrete as IHandlerTest<MessageBaseTest, ResponseMessageBaseTest>;
    }
}


public interface IHandlerTest<in TRequest, out TResponse>
where TRequest : MessageBaseTest
where TResponse : ResponseMessageBaseTest
{
    GenericResponse<TResponse> Handle(TRequest request);
}
public class HandlerTestConcrete<TRequest, TResponse> : IHandlerTest<TRequest, TResponse>
where TRequest : MessageBaseTest
where TResponse : ResponseMessageBaseTest
{
    public Task<GenericResponse<TResponse>> Handle(TRequest request)
    {
        throw new System.NotImplementedException();
    }
}

public class ResponseMessageBaseTest { }
public class MessageBaseTest { }

public class ResponseMessageBaseTestConcrete: ResponseMessageBaseTest { }
public class MessageBaseTestConcrete: MessageBaseTest { }

public interface GenericResponse<TResponse> where TResponse : ResponseMessageBaseTest
{
    TResponse Response { get; }
}

错误是

无效方差:类型参数 TResponse 在 IHandlerTest.Handle(TRequest) 上必须始终有效。 TResponse 是协变的

我的目的是用这行代码进行转换

var cast = handlerConcrete as IHandlerTest<MessageBaseTest, ResponseMessageBaseTest>;
c# generics covariance
1个回答
1
投票

由于多种原因这是不可能的。首先,类不支持 C# 中的方差,因此

Task
GenericResponse
都不能用作
Handle
的返回参数。后者可以通过引入一个界面来解决 -
public interface IGenericResponse<out TResponse> where TResponse : ResponseMessageBaseTest
,但对于
Task
来说,事情就没那么容易了。

但主要缺陷是

new HandlerTestConcrete<MessageBaseTestConcrete, ...>
不是
IHandlerTest<MessageBaseTest, ...>
,原因非常明显 - 它要求“至少”传入
MessageBaseTestConcrete
,因此传递
MessageBaseTest
打破了这一要求。但使用
MessageBaseTestConcrete
应该可以:

var cast = handlerConcrete as IHandlerTest<MessageBaseTestConcrete, ResponseMessageBaseTest>;

或任何继承人(

MessageBaseTestConcreteConcrete : MessageBaseTestConcrete
):

var cast = handlerConcrete as IHandlerTest<MessageBaseTestConcreteConcrete, ResponseMessageBaseTest>;
© www.soinside.com 2019 - 2024. All rights reserved.