我实际上要做的是编写一个允许我更改DataGridView中的选择的函数,我想编写一个函数并将其用于行和列。这是一个简单的示例,取消选择所有内容并选择新的行或列:
private void SelectNew<T>(T collection, int index) where T : IList
{
ClearSelection();
collection[index].Selected = true;
}
我的问题是这不起作用,因为无法导出.Selected()
可用,因为这是非通用的IList。
使用
where T : IList<DataGridViewBand>
会很好但是因为DataGridViewRowCollection(和-Column-)只是从IList派生而来,所以这不起作用。
在C ++中我可能会使用traits idiom。有没有办法在C#中做到这一点,还是有更惯用的方式?
答案 0 :(得分:5)
虽然理论上可以使用反射来做到这一点;因为你的明确目标只是处理行或列,最简单的选择就是为函数创建两个重载:
private void SelectNew(DataGridViewColumnCollection collection, int index)
{
ClearSelection();
collection[index].Selected = true;
}
private void SelectNew(DataGridViewRowCollection collection, int index)
{
ClearSelection();
collection[index].Selected = true;
}
如果您尝试使用反射来执行此操作,它将起作用,但它会更慢,更不可读,并且存在无编译时保护的危险;人们可以传入其他类型的列表,这些列表没有Selected
属性,它会编译并在运行时失败。
答案 1 :(得分:1)
一种可能性是使用dynamic
:
private void SelectNew(IList collection, int index)
{
ClearSelection();
((dynamic)collection)[index].Selected = true;
}
或者:
private void SelectNew(IList collection, int index)
{
ClearSelection();
DataGridViewBand toSelect = ((dynamic)collection)[index];
toSelect.Selected = true;
}
这样做的最大缺点是你失去了编译时类型的安全性,所以我不建议这样做,除非它阻止了大量的代码重复。
(第二个版本的编译时类型安全性更高,代价是更加冗长和明确。)
答案 2 :(得分:0)
如果您有一个实现IEnumerable
的集合,并且您提前知道它包含哪些类型的元素,您可以执行以下操作:
IList<DataGridViewBand> typedCollection = collection
.Cast<DataGridViewBand>()
.ToList();
允许您调用通用扩展方法:
private void SelectNew<T>(T collection, int index)
where T : IList<DataGridViewBand>
{
ClearSelection();
collection[index].Selected = true;
}
typedCollection.SelectNew(1);
编辑:
如果您决定在IList<DataGridViewBand>
上约束T,那么您也可以直接为该类型编写一个方法,因为您通过使用泛型获得了任何东西。
IList<DataGridViewBand> typedCollection = collection
.Cast<DataGridViewBand>()
.ToList();
private void SelectNew(IList<DataGridViewBand> collection, int index)
{
ClearSelection();
collection[index].Selected = true;
}
typedCollection.SelectNew(1);