我有一个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 :(得分: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 :(得分: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());
}
}
答案 2 :(得分: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);
}
}
}