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

C# 值类型接口上的协方差错误,c#,generics,type-conversion,covariance,value-type,C#,Generics,Type Conversion,Covariance,Value Type,我有一个通用接口,其中包含一个协变TValue参数和一个抽象类,该抽象类执行一些重复的操作,将子类从这个负担中解放出来。然后我有两个子类,它们是从抽象类扩展而来的,第一个将泛型参数设置为字符串,第二个设置为int 这是从项目中提取的代码的一个子部分,为了关注问题而过度简化 public interface IElement<out TValue> { string Name { get; } TValue Value { get; } } public abstra

我有一个通用接口,其中包含一个协变TValue参数和一个抽象类,该抽象类执行一些重复的操作,将子类从这个负担中解放出来。然后我有两个子类,它们是从抽象类扩展而来的,第一个将泛型参数设置为字符串,第二个设置为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") { }
}
公共接口IELENT
{
字符串名称{get;}
TValue值{get;}
}
公共抽象类元素:IEElement
{
公共字符串名称{get;}
公共TValue值{get;set;}
公共元素(字符串名称)
{
名称=名称;
}
}
公共类名:元素
{
public Name():基(“名称”){}
}
公共类高度:元素
{
公共高度():基准(“高度”){}
}
基本上-这不是我在代码中所做的,但相当简单地说明了我遇到的问题-如果我尝试将名称分配给一个IEElement持有对象,如下所示:

IElement<object> element = new Name();
IElement元素=新名称();
正如我所期望的那样,它成功了,因为IEElement中的TValue参数是协变的。 但是,如果我将其设置为高度:

IElement<object> element = new Height();
IElement元素=新高度();
我得到一个
无法隐式地将类型“Height”转换为“IElement”。存在显式转换(是否缺少转换?
错误

现在,我不知道为什么这个方法适用于将泛型参数设置为字符串的类,而不适用于int(或enum,我在项目中也有一些enum)。是因为string是一个类,int是一个结构吗

非常感谢您的帮助。

很简单,因为其中一个是值类型。CLR不允许它,因为它需要保留其标识,而装箱则不允许

有一个关于这方面的博客

接口和委托的协变和逆变转换 类型要求所有可变类型参数都是引用类型。 确保始终保持变量引用转换 保持身份,所有涉及类型参数的转换 还必须保持身份。确保所有 类型参数上的非平凡转换是保持身份的 是将它们限制为引用转换

此外,您可以在不同的地方阅读更多关于规范中的标识、转换、泛型和差异的信息

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

对于未知为引用类型的类型参数T (§15.2.5),以下涉及T的转换被视为 编译时的装箱转换(11.2.8)。在运行时,如果T是 值类型,转换将作为装箱转换执行。在 运行时,如果T是引用类型,则转换将作为 隐式引用转换或标识转换


看来我还有很多东西要学。虽然我理解你的解释,但其中还有很多概念我没有完全理解。谢谢你让我走上正轨!