【问题标题】:Why won't a class derived from an abstract class with a where clause cast to its lowest common class为什么从带有 where 子句的抽象类派生的类不能转换为其最低的公共类
【发布时间】:2012-01-23 15:56:38
【问题描述】:

复制问题的一些代码:

using System;

public abstract class Response { }
public abstract class Request<T> where T : Response { }
public class LoginResponse : Response { }
public class LoginRequest : Request<LoginResponse> { }

public class Program
{
    static void Main(string[] args)
    {
        LoginRequest login = new LoginRequest();


        /* Error: Cannot implicitly convert type 'LoginRequest' to 'Request' */
        Request<Response> castTest = login;


        /* No Error */
        Request<LoginResponse> castTest2 = login;
    }
}

据我所知,LoginRequest 类是 Request 因为它继承自 Request 而 LoginResponse 继承自 Response 所以任何人都可以告诉我为什么我得到编译器错误?

注意:我也尝试过显式转换

【问题讨论】:

    标签: c# inheritance abstract-class


    【解决方案1】:

    您收到错误是因为 Request&lt;Response&gt;Request&lt;LoginResponse&gt; 不是协变的。

    仅仅因为LoginResponse 继承自Response 并不意味着Request&lt;LoginResponse&gt; 可以被视为与Request&lt;Response&gt; 相同。阅读这篇文章:

    MSDN - Covariance and Contravariance in Generics

    【讨论】:

    • 谢谢,我对协方差的理解有点薄,我需要做更多的阅读。
    【解决方案2】:

    这是因为 C# 泛型类不是协变的。 C# 试图阻止您执行以下操作:

    Request<Response> castTest = login;
    castTest.Response = someOtherKindOfResponse;
    

    这个例子用列表可能更清楚。想象一下,如果以下方法有效:

    var someStringList = new List<String>();
    var someObjectList = ((List<Object>)someStringList; // This throws a compile exception, thankfully
    someObjectList.Add(1); // If the above worked, then this would compile, but would throw a runtime exception
    

    【讨论】:

    • 我喜欢列表示例,它更易于理解。
    【解决方案3】:

    因为您的泛型参数是隐式不变的 - Request&lt;LoginResponse&gt;Request&lt;Response&gt; 这两种类型是完全不同的。 C# 4.0 引入了委托类型和接口的差异,可以在这里为您提供解决方案:

    public interface IResponse<out T> where T : Response {}
    

    这里我们将泛型类型T 声明为Covariant

    Eric Lippert 就 C# 中的方差主题撰写了 many good blog posts,我强烈建议您阅读它们。

    【讨论】:

      【解决方案4】:

      LoginRequest 不是从Request&lt;Response&gt; 派生的,它是从Request&lt;LoginResponse&gt; 派生的。

      泛型类型在编译后本身就是一种类型。模板化的参数层次是无关紧要的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-11
        • 2021-06-21
        • 2020-09-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多