2009-08-29 30 views
0

假設您正在編寫一個庫以在屏幕上顯示內容,則創建一個IDisplayable接口。該接口有一種方法可以從對象創建控件:displayable.GetControl()僅適用於某些類型參數的方法的通用類

你想創建你自己的可以顯示的列表類型:MyList<T>。現在這個列表只能在TIDisplayable時顯示,所以你可以在MyList類中詢問T應該實現IDisplayable。但是,當T不是IDisplayable時,你也希望在某些地方使用這種列表類型(並且因此這個列表將不可顯示)。那麼如果T實現了IDisplayable,那麼有可能說MyList實現了IDisplayable?我也會很高興,如果MyList<T>總是實現IDisplayable,但在運行時拋出異常,如果你嘗試調用GetControl()如果T不是IDisplayable,但我想知道是否有靜態類型安全的方法來做到這一點。這可以做到嗎?或者我正在尋找錯誤的解決方案?

編輯:

我的建議同意迄今是MYLIST可能有太多的責任。我最初的想法是創建一個MyDisplayableList<T> : MyList<T> (where T : IDisplayable)

這種方法的問題是,我有很多采用MyList並返回MyList的方法(例如像Linq中的Select方法)。所以,如果我在MyDisplayableList上使用select,我會返回一個MyList,並且它們即使它是MyList也無法顯示它...是否有一種在C#中處理此問題的安全方法?

+1

爲什麼你也想用MYLIST 非顯示班?在我看來,你要求MyList 做太多事情,但沒有理由很難說。 – 2009-08-29 17:58:06

回答

5

簡單。檢查類型是否爲IDisplayable。如果不是的話,拋出InvalidOperationException

if (!typeof(IDisplayable).IsAssignableFrom(typeof(T))) 
    throw new InvalidOperationException(); 

或者,如果你有T一個實例,簡單地與檢查:

IDisplayable disp = instanceOfT as IDisplayable; 
if (disp == null) 
    throw new InvalidOperationException(); 
// do stuff with `disp`. 

您的設計可能是有缺陷的,雖然。你可能在課堂上太多,違反單一責任原則。首先重新檢查你的設計。

+0

謝謝,這就是我要使用的。但是,如果可用,我寧願採用靜態類型安全的方法... – Jules 2009-08-29 20:17:23

+0

無法強制執行此操作(對於某些類的某些特定方法)。類型約束在類型級別執行。 – 2009-08-29 20:21:44

8

這是不可能的,因爲你描述它。您應該創建兩種類型的列表:

public class MyList<T> : IList<T> 
{ 
    ... 
} 

public class MyDisplayableList<T> : MyList<T> where T : IDisplayable 
{ 
    ... 
} 
+0

啊,是的,謝謝你,這是我的第一個想法,但我沒有告訴你足夠的。這種方法的問題是我有很多方法需要MyList 並返回MyList (例如,在Linq中選擇的方法)。所以,如果我在MyDisplayableList上使用select,我返回一個MyList,並且我無法顯示它......是否有一種安全的方式來處理C#中的這個問題? – Jules 2009-08-29 20:20:09

+0

然後使該方法通用:'公共TList Foo (TList列表)其中TList:MyList ' – dtb 2009-08-29 20:39:18

+0

謝謝。然而,我不明白這將如何解決問題。例如,如果我做了'aMyList.Select((a)=> a.ToDisplayable())',那麼我會有一個'MyList ',但我不能在它上面調用GetControl(),因爲它不是MyDisplayableList。 – Jules 2009-08-29 20:54:37

1

您是否還需要仿製藥?

我猜你有多個類實現IDisplayable,並希望將它們的所有實例放在同一個列表中。所以,你只需要一個

public class MyList : Collection<IDisplayable>, IDisplayable 
{ 
    public void GetControl() 
    { 
     foreach (IDisplayable displayable in this) 
     { 
      displayable.GetControl(); 
     } 
    } 
} 

如果你真想把非IDisplayable情況下,在該列表中爲好,找到共同的基類,並定義一個

public class MyList2 : Collection<object>, IDisplayable 
{ 
    public void GetControl() 
    { 
     foreach (IDisplayable displayable in this.OfType<IDisplayable>()) 
     { 
      displayable.GetControl(); 
     } 
    } 
} 
1

我認爲原因你想MyList<T>能夠與IDisplayable和非IDisplayable一起工作是因爲有一些重複的功能。

我建議你的基本實現爲MyListBase<T>,它實現了列表執行的基本功能。然後,您的MyDisplayableList繼承MyList(MyDisplayableList<T> : MyList<T> where T : IDisplayable),該函數僅執行特定於IDisplayable的功能。

如果有任何特定於非IDisplayble的功能,請添加NonDisplayableList<T> : MyListBase<T>以執行這些功能。

1

我認爲解決這個問題的一個更好的辦法是從列表中抽象出來,然後想象一下IDisplayablecomposite。例如,這正是ASP.NET或Windows窗體中控件的建模方式。

public class CompositeDisplayable : IDisplayable { 

    public void Add(IDisplayable displayable) { 
    // TODO: check for null, cycles, etc... 
    _list.Add(displayable); 
    } 

    public void Remove(IDisplayable displayable) { 
    // TODO: check for null 
    _list.Remove(displayable); 
    } 

    public Control GetControl() { 
    var control = new Control(); 
    // this assumes Control is also a composite type 
    _list.ForEach(displayable => control.Add(displayable.GetControl())); 
    return control; 
    } 

    private List<IDisplayable> _list = new List<IDisplayable>(); 

} 

然後,你的「東西」的複合式集合之間的橋樑,你可以創建一個擴展方法是這樣的:

public static class DisplayableExtensions { 

    public static IDisplayable ToDisplayable(this IEnumerable source) { 
    if (source == null) throw new NullReferenceException(); // extension method should behave like instance methods 
    var result = new CompositeDisplayable(); 
    source. 
     OfType<IDisplayable>(). 
     ToList(). 
     ForEach(displayable => result.Add(displayable)); 
    return result; 
    } 

} 
相關問題