Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何获取旧样式集合中的项目类型?_C#_Generics_Type Constraints - Fatal编程技术网

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

C# 如何获取旧样式集合中的项目类型?,c#,generics,type-constraints,C#,Generics,Type Constraints,我实际上想做的是编写一个函数,允许我更改DataGridView中的选择,我想编写一个函数,并将其用于行和列。下面是一个简单的示例,可以取消选择所有内容并选择新行或新列: private void SelectNew<T>(T collection, int index) where T : IList { ClearSelection(); collection[index].Selected = true; } 这很好,但因为DataGridViewRowCollect

我实际上想做的是编写一个函数,允许我更改DataGridView中的选择,我想编写一个函数,并将其用于行和列。下面是一个简单的示例,可以取消选择所有内容并选择新行或新列:

private void SelectNew<T>(T collection, int index) where T : IList
{
  ClearSelection();
  collection[index].Selected = true;
}
这很好,但因为DataGridViewRowCollection(和-Column-)只是从IList派生的,所以这不起作用


在C++中,我可能会使用这些特征习语。在C语言中,有没有一种方法可以做到这一点?或者有没有一种更惯用的方法?

虽然理论上可以使用反射来做到这一点;由于您明确的目标只是处理行或列,因此最简单的选项是为函数创建两个重载:

private void SelectNew(DataGridViewColumnCollection collection, int index)
{
    ClearSelection();
    collection[index].Selected = true;
}

private void SelectNew(DataGridViewRowCollection collection, int index)
{
    ClearSelection();
    collection[index].Selected = true;
}

如果您试图使用反射来实现这一点,它会起作用,但速度会较慢,可读性较差,并且有没有编译时保护的危险;人们可以传递其他类型的列表,这些列表没有选择的
属性,它将编译并在运行时失败。

一种可能是使用
动态

private void SelectNew(IList collection, int index)
{
  ClearSelection();
  ((dynamic)collection)[index].Selected = true;
}
或:

这样做的最大缺点是您正在失去编译时类型安全性,因此我不建议这样做,除非它防止了大量代码重复


(第二个版本的编译时类型更安全,但代价是更详细、更明确。)

如果您有一个实现
IEnumerable
的集合,并且您提前知道它包含的元素类型,则可以执行以下操作:

IList<DataGridViewBand> typedCollection = collection
                                          .Cast<DataGridViewBand>()
                                          .ToList();
IList typedCollection=集合
.Cast()
.ToList();
这将允许您调用通用扩展方法:

private void SelectNew<T>(T collection, int index)
   where T : IList<DataGridViewBand>
{
  ClearSelection();
  collection[index].Selected = true;
}

typedCollection.SelectNew(1);
private void SelectNew(T集合,int索引)
其中T:IList
{
选举();
集合[索引]。已选择=真;
}
键入集合。选择新建(1);
编辑:

如果您决定将T约束在
IList
上,那么您也可以直接为该类型编写一个方法,因为使用泛型不会获得任何好处

IList<DataGridViewBand> typedCollection = collection
                                          .Cast<DataGridViewBand>()
                                          .ToList();

private void SelectNew(IList<DataGridViewBand> collection, int index)
{
  ClearSelection();
  collection[index].Selected = true;
}

typedCollection.SelectNew(1);
IList typedCollection=集合
.Cast()
.ToList();
私有void SelectNew(IList集合,int索引)
{
选举();
集合[索引]。已选择=真;
}
键入集合。选择新建(1);

不幸的是,C#泛型不支持任何形式的traits习惯用法-您必须使用必须是实现的接口或基类的约束。这是我目前的解决方案,但对于某些函数,它会导致相当多的代码重复,我希望避免这种情况。我决定采用这种方法。我认为重复的代码比复杂的解决方案更易于维护。然后你创建一个新的列表并复制其中的所有元素,只是为了访问和修改一个变量。最好只使用索引器获取一个值,然后根据需要对其进行强制转换。@Servy Correct,我希望我的答案能够澄清关于泛型的混淆,不过您的解决方案会更好。
private void SelectNew<T>(T collection, int index)
   where T : IList<DataGridViewBand>
{
  ClearSelection();
  collection[index].Selected = true;
}

typedCollection.SelectNew(1);
IList<DataGridViewBand> typedCollection = collection
                                          .Cast<DataGridViewBand>()
                                          .ToList();

private void SelectNew(IList<DataGridViewBand> collection, int index)
{
  ClearSelection();
  collection[index].Selected = true;
}

typedCollection.SelectNew(1);