我有一个通用类Zone<T> where T: Media.Medium
。在这个类中,我有一个方法public void AddNode(Node node)
,其中我有一个语句node.ParentZone = this
,它引发了这个编译错误:
无法隐式转换类型&#39;区域&lt; T&gt;&#39;至 &#39;&区LT; Media.Medium&gt;&#39;
但我无法理解为什么public abstract class Node
public Zone<Media.Medium> ParentZone
字段和Zone<T> where T: Media.Medium
字段受where T: Media.Medium
限制,因此T为Media.Medium
在任何情况下。
以下是孤立的代码:( 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>();
}
//在下面的行中编译错误
node.ParentZone = this;
//无法隐式转换类型&#39;区域&lt; T&gt;&#39;至 &#39;&区LT; Media.Medium&gt;&#39;
_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;
...
}
更新#1:
此代码的目标是:我想将Node
个对象添加到Zone
个对象,Zone
个对象具有Node
个对象的列表。每当我向Node
添加Zone
时,我都希望将Zone
对象设置为Node
对象的父对象。
我愿意为实现这一目标而进行任何重构。如果有更好的那个,就不应该这样。
答案 0 :(得分:3)
您应该清楚,通用约束不提供泛型类型之间的可分配性。或者表达不同:如果泛型类继承自另一个类并且共享相同的类型参数,则泛型类可分配给另一个类。例如:
class Zone<T> where T : Medium { }
class ChildZone<T>: Zone<T> where T : Medium { }
class Medium { }
class ChildMedium : Medium { }
什么有效:
Zone<Medium> mediumZone = new ChildZone<Medium>();
Zone<ChildMedium> childMediumZone = new ChildZone<ChildMedium>();
什么行不通:
Zone<Medium> mediumZone = new Zone<ChildMedium>();
ChildZone<Medium> childMediumZone = new ChildZone<ChildMedium>();
为什么呢?因为继承在泛型类中起作用,而不是泛型参数。考虑一下:
class Zone<T> {
T Value { get; set; }
}
Zone<Medium>
的实例可以在其Medium
属性中读取和类型Value
的项目。这意味着它可以同时读写Medium
和ChildMedium
。相反,Zone<ChildMedium>
只能读写ChildMedium
。这里的问题是setter,因为无法将Medium
分配给Zone<ChildMedium>.Value
,而不是分配给Zone<Medium>.Value
。这使得这些类型不兼容。
如果您的Zone
类是一个接口,并且您确保它只返回T类型的值,但您无法设置该类型的值,则可以使用covariance:< / p>
interface IZone<out T> {
T Value { get; }
}
如果您需要读取和写入值,您唯一的选择是使Node
也是通用的并传递通用约束:
namespace Core.Nodes
{
public abstract class Node<T> where T : Media.Medium
{
public Zone<T> ParentZone;
//...
}
}
答案 1 :(得分:2)
看起来你的Node类声明无效
public abstract class Node<T> where T: Media.Medium
{
public Zone<T> ParentZone;
...
}
答案 2 :(得分:1)
我认为这是一个经典的协方差/逆变问题。如果你不想让Node变得通用(也许它根本不是通用的?)那么试着摆弄这个:
https://docs.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance
如果您具体声明要尝试实现的目标,则可以更改示例并使其正常工作。它需要添加接口IZone
。
public interface IZone<out T> where T : Media.Medium
{
//important stuff here
}
public class Zone<T> : IZone<T> where T : Media.Medium
{
...
}
public abstract class Node
{
public IZone<Media.Medium> ParentZone;
}
答案 3 :(得分:1)
您已说过类型T
继承自Media.Medium
,而非Zone<T>
继承自Media.Medium
。这是一个简单的,有希望的说明性示例:
class Program
{
class A<T> where T: B
{
public void Foo(B b)
{
T t = Activator.CreateInstance<T>();
//this is OK
b = t;
//this is not
b = this;
}
}
class B
{
}
class C : B
{
public void Foo(B b)
{
//this is ok
b = this;
}
}
}