2014-01-18 117 views
16

這是類設計問題。通用接口繼承非泛型C#

我有主抽象類

public abstract class AbstractBlockRule 
{ 
    public long Id{get;set;} 
    public abstract List<IRestriction> Restrictions {get;}; 
} 

public interface IRestriction{} 

public interface IRestriction<T>:IRestriction where T:struct 
{ 
    T Limit {get;} 
} 

public TimeRestriction:IRestriction<TimeSpan> 
{ 
    public TimeSpan Limit{get;set;} 
} 

public AgeRestriction:IRestriction<int> 
{ 
    public int Limit{get;set;} 
} 

public class BlockRule:AbstractBlockRule 
{ 
    public virtual List<IRestriction> Restrictions {get;set;} 
} 

BlockRule rule=new BlockRule(); 
TimeRestriction t=new TimeRestriction(); 
AgeRestriction a=new AgeRestriction(); 

rule.Restrictions.Add(t); 
rule.Restrictions.Add(a); 

我必須使用非通用接口IRestriction只是爲了避免在主抽象類指定通用類型T。我對泛型非常陌生。有人能讓我知道如何更好地設計這件事嗎?

+1

對於我來說,很難改進你的代碼。非泛型基本接口可以有一個屬性'ValueType BoxedLimit {get;}'如果你想要,但我不確定它是否有用。畢竟,爲什麼你需要一個不同類型的對象的List <>? –

+0

(當然,由於C#和.NET不支持與值類型的協方差,因此當您將它與值類型(結構)一起使用時,使通用接口協變'IRestriction '不明顯。) –

+0

我不確定你爲什麼不製作抽象類或者通用的方法。 「限制」是最低還是最高?如果是這樣的話,「IComparable」可能會更有用。 –

回答

12

您的方法是典型的(例如,IEnumerable <T>像這樣實現了IEnumerable)。如果要爲代碼的使用者提供最大的實用程序,那麼在非通用接口上提供非通用訪問器將會很好,然後將其隱藏在通用實現中。例如:

public abstract class AbstractBlockRule 
{ 
    public long Id{get;set;} 
    public abstract List<IRestriction> Restrictions { get; set; } 
} 

public interface IRestriction 
{ 
    object Limit { get; } 
} 

public interface IRestriction<T> : IRestriction 
    where T:struct 
{ 
    // hide IRestriction.Limit 
    new T Limit {get;} 
} 

public abstract class RestrictionBase<T> : IRestriction<T> 
    where T:struct 
{ 
    // explicit implementation 
    object IRestriction.Limit 
    { 
     get { return Limit; } 
    } 

    // override when required 
    public virtual T Limit { get; set; } 
} 

public class TimeRestriction : RestrictionBase<TimeSpan> 
{ 
} 

public class AgeRestriction : RestrictionBase<TimeSpan> 
{ 
} 

public class BlockRule : AbstractBlockRule 
{ 
    public override List<IRestriction> Restrictions { get; set; } 
} 

我也在這裏顯示了使用基礎限制類,但它不是必需的。

0

接口是實施合同的實體需要遵循的合同。

您已經創建了兩個合同具有相同的名稱IRestriction

據我所看到的,你是什麼基本上可能需要的是一個班一個標誌,可以被限制,這應實施IRestriction非通用接口。

第二個界面似乎是也包含限制屬性的可限制對象。因此,第二個接口的定義可以是ILimitRestriction或任何適合您的業務需求的名稱。

因此ILimitRestriction可以從IRestriction繼承這將標誌着類繼承ILimitRestriction靜物的IRestriction

public abstract class AbstractBlockRule 
{ 
    public long Id{get;set;} 
    public abstract List<IRestriction> Restrictions {get;}; 
} 

public interface IRestriction{} 

public interface IRestrictionWithLimit<T>:IRestriction where T:struct 
{ 
    T Limit {get;} 
} 

public TimeRestriction:IRestrictionWithLimit<TimeSpan> 
{ 
    public TimeSpan Limit{get;set;} 
} 

public AgeRestriction:IRestrictionWithLimit<int> 
{ 
    public int Limit{get;set;} 
} 

public class BlockRule:AbstractBlockRule 
{ 
    public virtual List<IRestriction> Restrictions {get;set;} 
} 
2

運行時將IRestriction<TimeSpan>IRestriction<int>不同的不同類別的(他們甚至有自己的一套靜態變量)。在你的情況下,在繼承層次結構中IRestriction<TimeSpan>IRestriction<int>共有的唯一類是IRestrictionobject

確實,列出IRestriction是唯一明智的方法。


作爲一個方面說明:您有一個屬性Limit在那裏,你可能想訪問無論你在處理一個IRestriction<TimeSpan>IRestriction<int>的。在這種情況下,我會做的是在IRestriction上定義另一個屬性object Limit { get; },並將其隱藏在實際實現中。就像這樣:

public interface IRestriction 
{ 
    object Limit { get; } 
} 

public interface IRestriction<T> : IRestriction 
    where T : struct 
{ 
    new T Limit { get; set; } 
} 

public class TimeRestriction : IRestriction<TimeSpan> 
{ 
    public TimeSpan Limit { get; set; } 

    // Explicit interface member: 
    // This is hidden from IntelliSense 
    // unless you cast to IRestriction. 
    object IRestriction.Limit 
    { 
     get 
     { 
      // Note: boxing happens here. 
      return (object)Limit; 
     } 
    } 
} 

這樣你就可以在所有的IRestriction訪問Limitobject,當你不關心它是什麼類型。例如:

foreach(IRestriction restriction in this.Restrictions) 
{ 
    Console.WriteLine(restriction.Limit); 
}