2011-06-13 19 views
2

父子數據結構,我有以下示例關係:沒有明確的使用葉節點類泛型

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被實現as

public sealed class Atom : Entity<Particle> 

由此

Entity<Atom> 

預計分解成

Entity<Entity<Particle>> 
+0

你想做什麼?你的結構是錯誤的 – 2011-06-13 13:54:03

回答

0

儘管Daniel Martin發佈的潛在解決方案無法工作(正如公認的警告),但爲什麼我的代碼永遠不會工作的解釋是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); 
     } 
    } 
} 

感謝丹尼爾·馬丁。由於我目前的代表,我無法提供給您。得分了。對於那些想知道的,以上是一個愚蠢的模擬,旨在突出明顯的親子關係,以幫助那些理解這個問題的人。真實世界的預期用途將是計算機圖形學領域將採用的高級版本,以定義明確且遞歸的方式解決相干空間分區問題。

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>。基本問題是,雖然MoleculeEntity<Atom>,但編譯器無法知道Molecule也是Entity<Entity<Particle>>。畢竟,假設Entity保持了一個孩子的名單,並有明智的addChild(T child)方法。然後編譯器希望確保您只添加Atom作爲分子的子代。但是,如果MoleculeEntity<Entity<Particle>>,那麼沒有什麼能夠阻止你這樣做的:

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

此模式的正確完全類型安全的解決方案涉及自我類型,其Java和C#不具備的。 Java模式的Foo<F extends Foo<F>>and its C# equivalent)接近,但非常易於使用。除此之外,聲明時間差異會使此模式更清晰。

相關問題