如何获取旧样式集合中的项目类型?

时间:2013-06-24 16:30:02

标签: c# generics type-constraints

我实际上要做的是编写一个允许我更改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#中做到这一点,还是有更惯用的方式?

3 个答案:

答案 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);