2009-06-18 60 views
0

我有一個DataGridView,我想用它來存儲通用數據。我想在DataGridView類中保存一個類型化的數據列表,以便所有類型等都可以在內部處理。但我不想在DataGridView上設置類型,因爲在調用InitializeData方法之前我不會知道數據類型。將通用數據存儲在非泛型類中

public class MyDataGridView : DataGridView { 
    private List<T> m_data; 
    public InitializeData<T>(List<T> data) { 
     m_data = data; 
    } 
    ... internal events to know when the datagrid wants to sort ... 
    m_data.Sort<T>(...) 
} 

這可能嗎?如果是這樣,怎麼樣?

+0

如果你可以擴展你如何設想被調用的Sort方法將是很有幫助的。你呼叫什麼樣的超載,參數來自哪裏。 – kvb 2009-06-18 17:04:34

+0

排序方法將使用一個使用反射來排序列表的GenericComparer。比較器爲屬性進行排序並使用SortOrder進行升序或降序。數據網格視圖列具有與它們相關聯的屬性,所以當點擊列時,我從列信息中提取屬性和排序順序。 – ericmck 2009-06-18 17:30:33

回答

4

如果在調用InitializeData之前不知道該類型,那麼該類型顯然不能是該對象的編譯時部分。

當您撥打InitializeData<T>時,您是否知道所有需要了解的排序內容?如果是這樣,你怎麼樣做這樣的事情:

private IList m_data; 
private Action m_sorter; 

public InitializeData<T>(List<T> data) 
{ 
    m_data = data; 
    // This captures the data variable. You'll need to 
    // do something different if that's not good enough 
    m_sorter =() => data.Sort(); 
} 

然後當以後需要進行排序,你可以叫m_sorter()

如果您可能對不同事物進行排序,則可能會將其從Action更改爲Action<string>或任何您需要能夠排序的內容。

1

如果喬恩的答案是不夠的,這裏有一個更普遍(但更復雜,而且可能有點更加混亂)的方法:

/// <summary> 
/// Allows a list of any type to be used to get a result of type TResult 
/// </summary> 
/// <typeparam name="TResult">The result type after using the list</typeparam> 
interface IListUser<TResult> 
{ 
    TResult Use<T>(List<T> list); 
} 

/// <summary> 
/// Allows a list of any type to be used (with no return value) 
/// </summary> 
interface IListUser 
{ 
    void Use<T>(List<T> list); 
} 

/// <summary> 
/// Here's a class that can sort lists of any type 
/// </summary> 
class GenericSorter : IListUser 
{ 
    #region IListUser Members 

    public void Use<T>(List<T> list) 
    { 
     // do generic sorting stuff here 
    } 

    #endregion 
} 

/// <summary> 
/// Wraps a list of some unknown type. Allows list users (either with or without return values) to use the wrapped list. 
/// </summary> 
interface IExistsList 
{ 
    TResult Apply<TResult>(IListUser<TResult> user); 
    void Apply(IListUser user); 
} 

/// <summary> 
/// Wraps a list of type T, hiding the type itself. 
/// </summary> 
/// <typeparam name="T">The type of element contained in the list</typeparam> 
class ExistsList<T> : IExistsList 
{ 

    List<T> list; 

    public ExistsList(List<T> list) 
    { 
     this.list = list; 
    } 

    #region IExistsList Members 

    public TResult Apply<TResult>(IListUser<TResult> user) 
    { 
     return user.Use(list); 
    } 

    public void Apply(IListUser user) 
    { 
     user.Use(list); 
    } 

    #endregion 
} 

/// <summary> 
/// Your logic goes here 
/// </summary> 
class MyDataGridView 
{ 
    private IExistsList list; 
    public void InitializeData<T>(List<T> list) 
    { 
     this.list = new ExistsList<T>(list); 
    } 

    public void Sort() 
    { 
     list.Apply(new GenericSorter()); 
    } 
} 
0

你應該定義delgates或接口,你需要的任何通用操作在運行時執行。正如Jon Skeet所說,如果您不知道編譯時的類型,就不能強制鍵入數據網格。

這是框架執行此操作的方式。例如:

Array.Sort(); 

有幾個方面,它可用於:

這是您如何解決問題的示例。在最基本的層面上,您的場景可以通過strategy pattern來解決,這就是Array.Sort()所做的。

如果您需要在運行時動態地對事物進行排序,我會創建一個IComparer類,它將您想要排序的列作爲其構造函數中的參數。然後在你的比較方法中,使用該列作爲排序類型。

下面是一個如何使用一些基本示例類來實現它的示例。一旦你建立了這些類,你就可以將它們傳遞到數據網格中並在適當的時候使用它們。

public class Car 
{ 
    public string Make { get; set; } 
    public string Model { get; set; } 
    public string Year { get; set; } 
} 

public class CarComparer : IComparer 
{ 
    string sortColumn; 

    public CarComparer(string sortColumn) 
    { 
     this.sortColumn = sortColumn; 
    } 

    public int Compare(object x, object y) 
    { 
     Car carX = x as Car; 
     Car carY = y as Car; 
     if (carX == null && carY == null) 
      return 0; 
     if (carX != null && carY == null) 
      return 1; 
     if (carY != null && carX == null) 
      return -1; 

     switch (sortColumn) 
     { 
      case "Make": 
       return carX.Make.CompareTo(carY.Make); 
      case "Model": 
       return carX.Model.CompareTo(carY.Model); 
      case "Year": 
      default: 
       return carX.Year.CompareTo(carY.Year); 
     } 
    } 
}