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

C# 没有使用泛型的显式叶节点类的父子数据结构,c#,c#-4.0,covariance,generics,C#,C# 4.0,Covariance,Generics,我有以下示例关系: namespace Yesod { public class Program { // // // public struct Particle { public byte type; } // // // public class Entity<T>

我有以下示例关系:

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

        }
    }
}
namespace-Yesod
{
公共课程
{
//
//
//
公共结构粒子
{
公共字节类型;
}
//
//
//
公共类实体
{
公共实体母公司
{get;私有集;}
//
//
//
公共实体(实体父实体)
{
这个。父=父;
}
}
//
//
//
公共密封类Atom:实体
{
公共原子(实体父级)
:base(parent)//编译错误。
{ }
}
//
//
//
公共密封类分子:实体
{
公共分子()
:base(空)
{ }
}
静态void Main(字符串[]参数)
{
}
}
}
如何解决上面产生的以下编译错误

  Argument 1: cannot convert from 'Yesod.Program.Entity<Yesod.Program.Atom>' to 'Yesod.Program.Entity<Yesod.Program.Entity<Yesod.Program.Particle>>'
参数1:无法从'Yesod.Program.Entity'转换为'Yesod.Program.Entity'
评论回复#1: 具体来说,代码试图分配类型为的对象

Entity<Atom>
Entity<Entity<Particle>>
实体
类型的对象

Entity<Atom>
Entity<Entity<Particle>>
实体
as-Atom实现为

public sealed class Atom : Entity<Particle>
公共密封类原子:实体
据此

Entity<Atom>
实体
预计将细分为

Entity<Entity<Particle>>
实体
我不懂C,但Java程序员偶尔也会猛烈抨击这个问题

环顾其他C#来源,我认为您可以通过以下方式做您想要做的事情(在类型安全方面稍有损失):

这种模式的正确的完全类型安全解决方案包括自类型,而Java和C#没有自类型。
Foo
()的Java模式非常接近,但使用起来非常不方便。除此之外,声明时间差异将使此模式更清晰。

我不知道C#,但Java程序员偶尔也会遇到这个问题

环顾其他C#来源,我认为您可以通过以下方式做您想要做的事情(在类型安全方面稍有损失):


这种模式的正确的完全类型安全解决方案包括自类型,而Java和C#没有自类型。
Foo
()的Java模式非常接近,但使用起来非常不方便。除此之外,声明时间差异将使此模式更清晰。

尽管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);
        }
    }
}
namespace-Yesod
{
公共课程
{
//
//
//
公共结构粒子
{
公共字节类型;
}
//用C#4.0使用out关键字进行修复。
//
//
公共界面的开放性
{
亲本
{get;}
}
//
//
//
公共类实体:通用性
{
公母
{get;私有集;}
//
//
//
公共实体(企业母公司)
{
这个。父=父;
}
}
//
//
//
公共密封类Atom:实体
{
公共原子(实体父级)
:base(parent)//不再有编译错误。
{ }
}
//
//
//
公共密封类分子:实体
{
公共分子()
:base(空)
{ }
}
//
//
//
静态void Main(字符串[]参数)
{
//现在可以这样做了。
水分子=新分子();
原子H1=新原子(水);
原子O1=新原子(水);
原子O2=新原子(水);
}
}
}

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

尽管丹尼尔·马丁发布的潜在解决方案永远不会起作用(正如公认的警告),关于为什么我的代码永远无法工作的解释是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);
        }
    }
}
namespace-Yesod
{
公共课程
{
//
//
//
公共结构粒子
{
公共字节类型;
}
//用C#4.0使用out关键字进行修复。
//
//
公共界面的开放性
{
亲本
{get;}
}
//
//
//
公共类实体:通用性
{
公母
{get;私有集;}
//
//
//
公共实体(企业母公司)
{
这个。父=父;
}
}
//
//
//
公共密封类Atom:实体
{
公共原子(实体父级)
:base(parent)//不再有编译错误。
{ }
}
//
//
//
公共密封类分子:实体
{
公共分子()
:base(空)
{ }
}
//
//