值类型接口上的协方差错误

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

我有一个通用接口,该接口包含一个协变TValue参数和一个抽象类,该类做了一些重复的工作以使子类从该负担中解放出来。然后,我有2个从该抽象类扩展的子类,第一个将通用参数设置为字符串,第二个将int设置为int。

这是从项目中提取的代码的一个子部分,为了专注于此而过度简化。

public interface IElement<out TValue>
{
    string Name { get; }
    TValue Value { get; }
}

public abstract class Element<TValue> : IElement<TValue>
{
    public string Name { get; }
    public TValue Value { get; set; }

    public Element(string name)
    {
        Name = name;
    }
}

public class Name : Element<string>
{
    public Name() : base("Name") { }
}

public class Height : Element<int>
{
    public Height() : base("Height") { }
}

[基本上-这不是我在代码中所做的,而是相当简单地说明了我所遇到的问题-如果我尝试将Name分配给这样的IElement持有对象:

IElement<object> element = new Name();

由于IElement中的TValue参数是协变的,所以它成功了,正如我所期望的。但是,如果我将其设置为“高度”:

IElement<object> element = new Height();

我收到Cannot implicitly convert type 'Height' to 'IElement<object>'. An explicit conversion exists (are you missing a cast?)错误。

现在,我不知道为什么它可以与将通用参数设置为字符串的类一起使用,而不能与int(或者我在项目中也有一些枚举的枚举)一起使用。是因为string是一个类,而int是一个结构?

非常感谢您的帮助。

c# generics type-conversion covariance value-type
1个回答
1
投票

简单来说,因为一个是值类型。 CLR禁止使用它,因为它将需要保留其身份,而装箱则不需要。

[Eric LippertRepresentation and identity上有个很棒的博客

接口和委托的协变和协变转换类型要求所有不同的类型参数都是引用类型。为了确保始终提供变体参考转换保留身份,所有涉及类型实参的转换还必须保持身份。确保所有内容的最简单方法类型参数的非平凡转换是保留身份的是限制它们为参考转换。

此外,您可以在不同地方阅读更多有关规范中的身份,转换,泛型和差异的信息>>

[11.2.11涉及类型参数的隐式转换

对于未知为参考类型的类型参数T(第15.2.5节),涉及T的以下转换被认为是编译时进行装箱转换(11.2.8)。在运行时,如果T为a值类型,该转换将作为装箱转换执行。在运行时,如果T是引用类型,则转换将作为隐式引用转换或身份转换。

© www.soinside.com 2019 - 2024. All rights reserved.