没有使用泛型的显式叶节点类的父子数据结构

发布于 2024-11-15 05:12:55 字数 1668 浏览 1 评论 0 原文

我有以下示例关系:

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: 具体来说,代码尝试将 Atom 类型的对象分配

Entity<Atom>

类型的对象

Entity<Entity<Particle>>

给Atom

public sealed class Atom : Entity<Particle>

,预计

Entity<Atom>

会分解为

Entity<Entity<Particle>>

I have the following example relationship:

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)
        {

        }
    }
}

How would I solve the following compile error that the above produces?

  Argument 1: cannot convert from 'Yesod.Program.Entity<Yesod.Program.Atom>' to 'Yesod.Program.Entity<Yesod.Program.Entity<Yesod.Program.Particle>>'

Comment Reply #1:
Specifically, the code is trying to assign an object of type

Entity<Atom>

to an object of type

Entity<Entity<Particle>>

as Atom is implemented as

public sealed class Atom : Entity<Particle>

whereby

Entity<Atom>

is expected to breakdown into

Entity<Entity<Particle>>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

嘴硬脾气大 2024-11-22 05:12:55

我不懂 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 答案将涉及 ?扩展实体。基本问题是,尽管 Molecule 是一个 Entity,但编译器无法知道 Molecule 也是一个 >实体<实体<粒子>。毕竟,假设 Entity 维护了一个子级列表,并且具有合理的 addChild(T child) 方法。然后编译器会希望确保您只添加原子作为分子的子代。但是,如果 MoleculeEntity>,那么没有什么可以阻止您这样做:

Entity<Entity<Particle>> downcast = myMolecule;
downcast.addChild(myNonAtomParticleBasedEntity);

此模式的正确完全类型安全解决方案涉及 self 类型,Java 和 C# 没有。 Java 模式 Foo> (及其 C# 等效项)很接近,但工作起来很滑。除此之外,声明时间差异将使这种模式更加清晰。

I don't know C#, but Java programmers occasionally slam into this issue too.

Looking around at other C# sources, I think you can do what you want (with a little loss in type safety) with:

    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;
        }
    }

The Java answer would involve ? extends Entity<T>. The basic issue is that although Molecule is an Entity<Atom>, there's no way for the compiler to know that Molecule is also an Entity<Entity<Particle>>. After all, suppose that Entity maintained a list of children, and had the sensible addChild(T child) method on it. Then the compiler would want to ensure that you only added Atoms as children of molecules. But if Molecule is an Entity<Entity<Particle>>, then nothing would prevent you from doing:

Entity<Entity<Particle>> downcast = myMolecule;
downcast.addChild(myNonAtomParticleBasedEntity);

The proper fully type-safe solution for this pattern involves self types, which Java and C# don't have. The Java pattern of Foo<F extends Foo<F>> (and its C# equivalent) comes close, but is very slippery to work with. Barring that, declare-time variance would make this pattern cleaner.

灵芸 2024-11-22 05:12:55

尽管 Daniel Martin 发布的潜在解决方案永远不会起作用(诚然警告过),但对为什么我的代码也永远不会起作用的解释是 100% 准确的,它让我发现 C# 4.0 使用其新功能解决了这个原本预期的功能。 通用协方差&逆变 语言特征。

以下是解决方案,供审查:

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);
        }
    }
}

谢谢丹尼尔·马丁。由于我目前的代表,我无法对你进行 1 比。分数。对于那些想知道的人来说,上面是一个愚蠢的模型,旨在突出明显的亲子关系,以帮助人们理解这个问题。现实世界的预期用途将是一个高级版本,将用于计算机图形学领域,以明确定义的递归方式解决相干空间划分问题。

Although the potential solution posted by Daniel Martin would never work (as admittedly warned), the explanation on why my code would too never work is 100% accurate, and it has led me to discover that C# 4.0 solves this otherwise expected functionality using its new generic covariance & contra-variance language features.

Below is the solution, for review:

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);
        }
    }
}

Thanks Daniel Martin. I could not 1-up you due to my current rep. score. To those wondering, the above is a silly mock up aimed to highlight obvious parent-child relationships to help those understand the question. The real-world intended use will be an advanced version that will be employed in the field of computer graphics to solve the Coherent Space Partitioning problem in a well-defined and recursive manner.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文