2009-06-18 4 views
0

일반 데이터를 저장하는 데 사용할 DataGridView가 있습니다. 모든 정렬 등을 내부적으로 처리 할 수 ​​있도록 DataGridView 클래스에 형식화 된 데이터 목록을 유지하려고합니다. 하지만 InitializeData 메서드가 호출 될 때까지 데이터 형식을 알 수 없으므로 DataGridView에 형식을 설정하지 않아도됩니다.제네릭 데이터를 비 generic 클래스에 저장

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

+0

정렬 메서드는 리플렉션을 사용하여 목록을 정렬하는 GenericComparer를 사용합니다. 비교 자는 정렬 할 속성의 문자열 값과 오름차순 또는 내림차순의 SortOrder를 사용합니다. 데이터 격자보기 열은 열 속성과 연관된 속성을 가지므로 열을 클릭하면 열 정보에서 속성 및 정렬 순서를 추출합니다. – ericmck

답변

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>으로 변경하거나 정렬해야하는 항목을 변경할 수 있습니다.

+0

데이터는 사용자가 다양한 열을 클릭하여 정렬되므로 초기화 된 후에 메서드 및 이벤트에서 데이터에 액세스해야합니다. 그래서 저는 그것을 수업의 개인 회원으로 저장해야합니다. – ericmck

+0

그러나 시작 유형을 모르는 경우 해당 메소드가 강하게 입력 된 방식으로 어떻게 작동 할 수 있습니까? –

+0

리플렉션을 사용하여 일반 객체 목록을 정렬하는 GenericComparer 클래스가 있으므로. 정렬해야하는 속성은 데이터 격자보기의 열과 연결되므로 사용자가 클릭 한 열의 정보를 사용하여 GenericComparer와 함께 목록을 정렬하고 정렬 된 데이터를 표시합니다. – ericmck

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(); 

몇이 사용할 수있는 방법이 있습니다

  • 이 그것을 IComparable 또는
  • IComparable<T> 클래스는 두 번째 매개 변수에 보내기 구현하는 객체의 배열을 보내기를 그 IComparer 또는 IComparer<T>을 구현합니다. 정렬을 위해 객체를 비교하는 데 사용됩니다.
  • 배열의 개체를 비교하는 데 사용할 수있는 Comparison<T> 대리자 인 두 번째 매개 변수를 보냅니다.

다음은이 문제에 대한 예입니다. 가장 기본적인 수준에서 시나리오는 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); 
     } 
    } 
} 
관련 문제