无法隐式转换类型 - 泛型

fer*_*rit 4 c# generics

我有一个通用类Zone<T> where T: Media.Medium。在这个类中,我有一个方法public void AddNode(Node node),其中有一个node.ParentZone = this引发此编译器错误的语句:

无法将类型“Zone< T >”隐式转换为“Zone< Media.Medium >”

但我不明白为什么 aspublic abstract class Nodepublic Zone<Media.Medium> ParentZone字段和类Zone<T> where T: Media.Medium受 约束where T: Media.Medium,所以 TMedia.Medium在任何情况下都是 a 。

这是独立的代码:(完整Zone<T>且相关部分Node

public class Zone<T> where T: Media.Medium
{
    public readonly Type MediaType = typeof(T);
    public readonly Guid ID = new Guid();

    private readonly List<Node> _nodes = new List<Node>();

    public void AddNode(Node node)
    {
        foreach (var port in node.GetPorts())
        {
            port.Medium = Activator.CreateInstance<T>();
        }
Run Code Online (Sandbox Code Playgroud)

// 下面这行编译错误

        node.ParentZone = this; 
Run Code Online (Sandbox Code Playgroud)

// 无法将类型 'Zone< T >' 隐式转换为 'Zone< Media.Medium >'

        _nodes.Add(node);
    }



    public List<Node> GetNodes() => new List<Node>(_nodes);

    public void RemoveNode(Node node) => _nodes.Remove(node);


}





public abstract class Node
{       
    public Zone<Media.Medium> ParentZone;

    ...
}
Run Code Online (Sandbox Code Playgroud)

更新#1:

这段代码的目标是:我想将Node对象添加到Zone对象,Zone对象有一个对象列表Node。每当我将 a 添加Node到 a时Zone,我想将该Zone对象设置为该对象的父对象Node

我对实现这一目标的任何重构持开放态度。如果有更好的方式的话,它不应该是这样的。

Sef*_*efe 5

您应该清楚,泛型约束不提供泛型类型之间的可分配性。或者以不同的方式表达:如果泛型类从另一个类继承并共享相同的类型参数,则它可以分配给另一个类。例如:

class Zone<T> where T : Medium { }

class ChildZone<T>: Zone<T>  where T : Medium { }

class Medium { }

class ChildMedium : Medium { }
Run Code Online (Sandbox Code Playgroud)

什么有效:

Zone<Medium> mediumZone = new ChildZone<Medium>();
Zone<ChildMedium> childMediumZone = new ChildZone<ChildMedium>();
Run Code Online (Sandbox Code Playgroud)

什么不起作用:

Zone<Medium> mediumZone = new Zone<ChildMedium>();
ChildZone<Medium> childMediumZone = new ChildZone<ChildMedium>();
Run Code Online (Sandbox Code Playgroud)

为什么?因为继承在泛型类中起作用,而不是在泛型参数中起作用。考虑一下:

class Zone<T> {
   T Value { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

的实例Zone<Medium>可以读取Medium写入其属性中的类型的项目Value。这意味着它可以读取和写入MediumChildMedium。相比之下,Zone<ChildMedium>只能读取和写入ChildMedium。这里的问题是 setter,因为不可能分配MediumZone<ChildMedium>.Value,但不能分配给 to Zone<Medium>.Value。这使得类型不兼容。

如果您的Zone类是一个接口,并且您确保它只返回类型 T 的值,但您无法设置该类型的值,则可以使用协方差

interface IZone<out T> {
    T Value { get; }
}
Run Code Online (Sandbox Code Playgroud)

如果您需要读取和写入该值,您唯一的选择就是Node也通用并传递通用约束:

namespace Core.Nodes
{
    public abstract class Node<T> where T : Media.Medium
    {       
        public Zone<T> ParentZone;

        //...
    }
}
Run Code Online (Sandbox Code Playgroud)