我有以下示例关系:
namespace Yesod
{
public class Program
{
//
//
//
public struct Particle
{
public byte type;
}
//
//
//
public class Entity<T>
{
public Entity<Entity<T>> Parent
{ get; private set; }
//
//
//
public Entity(Entity<Entity<T>> parent)
{
this.Parent = parent;
}
}
//
//
//
public sealed class Atom : Entity<Particle>
{
public Atom(Entity<Atom> parent)
: base(parent) // Compile Error.
{ }
}
//
//
//
public sealed class Molecule : Entity<Atom>
{
public Molecule()
: base(null)
{ }
}
static void Main(string[] args)
{
}
}
}
如何解决上面产生的以下编译错误?
Argument 1: cannot convert from 'Yesod.Program.Entity<Yesod.Program.Atom>' to 'Yesod.Program.Entity<Yesod.Program.Entity<Yesod.Program.Particle>>'
评论回复#1: 具体来说,代码正在尝试分配类型为
的对象Entity<Atom>
到
类型的对象Entity<Entity<Particle>>
Atom实现为
public sealed class Atom : Entity<Particle>
,由此
Entity<Atom>
预计将分解为
Entity<Entity<Particle>>
答案 0 :(得分:0)
我不知道C#,但Java程序员偶尔也会遇到这个问题。
环顾其他C#来源,我认为你可以做到你想要的东西(在类型安全方面有一点损失):
public class Entity<T>
{
public Entity<P> Parent
where P : Entity<Entity<T>>
{ get; private set; }
//
//
//
public Entity(Entity<P> parent)
where P : Entity<Entity<T>>
{
this.Parent = parent;
}
}
Java答案将涉及? extends Entity<T>
。基本问题是虽然Molecule
是Entity<Atom>
,但编译器无法知道Molecule
也是Entity<Entity<Particle>>
。毕竟,假设Entity
维护了一个孩子列表,并且有一个明智的addChild(T child)
方法。然后编译器会希望确保您只添加Atom
s作为分子的子项。但如果Molecule
是Entity<Entity<Particle>>
,那么没有什么可以阻止你这样做:
Entity<Entity<Particle>> downcast = myMolecule;
downcast.addChild(myNonAtomParticleBasedEntity);
适用于此模式的完全类型安全的解决方案涉及自我类型,Java和C#没有。 Foo<F extends Foo<F>>
(and its C# equivalent)的Java模式非常接近,但使用起来非常滑。除此之外,声明时间差异会使这种模式更清晰。
答案 1 :(得分:0)
尽管丹尼尔·马丁发布的潜在解决方案永远不会起作用(正如已经警告过的那样),但为什么我的代码永远无法工作的解释是100%准确的,这让我发现C#4.0解决了这个原本预期的功能使用新的generic covariance & contra-variance语言功能。
以下是解决方案,供审核:
namespace Yesod
{
public class Program
{
//
//
//
public struct Particle
{
public byte type;
}
// Fix with C# 4.0 using out keyword.
//
//
public interface IEntity<out T>
{
IEntity<IEntity<T>> Parent
{ get; }
}
//
//
//
public class Entity<T> : IEntity<T>
{
public IEntity<IEntity<T>> Parent
{ get; private set; }
//
//
//
public Entity(IEntity<IEntity<T>> parent)
{
this.Parent = parent;
}
}
//
//
//
public sealed class Atom : Entity<Particle>
{
public Atom(Entity<Atom> parent)
: base(parent) // No more compile error.
{ }
}
//
//
//
public sealed class Molecule : Entity<Atom>
{
public Molecule()
: base(null)
{ }
}
//
//
//
static void Main(string[] args)
{
// Now this can be done.
Molecule water = new Molecule();
Atom H1 = new Atom(water);
Atom O1 = new Atom(water);
Atom O2 = new Atom(water);
}
}
}
谢谢Daniel Martin。由于我目前的代表,我无法帮助你。得分了。对于那些想知道的人,上面是一个愚蠢的模拟,旨在强调明显的亲子关系,以帮助那些人理解这个问题。现实世界的预期用途将是一个高级版本,将用于计算机图形领域,以明确定义和递归的方式解决相干空间分区问题。