简体   繁体   English

c# - LINQ select 来自集合

[英]c# - LINQ select from Collection

I'm attempting to write a simple Select method on a class that inherits from IList .我正在尝试在继承自IList的 class 上编写一个简单的Select方法。

public class RowDataCollection : IList<RowData> {
  private List<RowData> rowList;

  internal RowDataCollection(List<RowData> data) {
    rowList = data;
  }
  // ...
}

public RowDataCollection Rows;

public RowDataCollection Select(string colName, object value) {
  List<RowData> rowList = from item in Rows
         where item[colName].Value == value
         select item;
  return new RowDataCollection(rowList);
}

Some problems I'm having:我遇到的一些问题:

First:第一的:

  • VS2010 reports Cannot implicitly convert type 'IEnumerable<RowData>' to 'List<RowData>'. An explicit conversion exists (are you missing a cast?) VS2010 报告Cannot implicitly convert type 'IEnumerable<RowData>' to 'List<RowData>'. An explicit conversion exists (are you missing a cast?) Cannot implicitly convert type 'IEnumerable<RowData>' to 'List<RowData>'. An explicit conversion exists (are you missing a cast?)

OK, where does the CAST go?好的,CAST go 在哪里?

Second:第二:

  • Someone could pass in an invalid colName value (ie String.IsNullOrEmpty(colName) ) or a null parameter (object value == null) .有人可能传入无效的colName值(即String.IsNullOrEmpty(colName) )或 null 参数(object value == null)

How would I handle the way my function returns if the input parameters are invalid?如果输入参数无效,我将如何处理我的 function 返回的方式?

[Solved] [解决了]

I edited my Select statement (even renamed it per the suggestions here).我编辑了我的Select语句(甚至根据此处的建议将其重命名)。 I had to use a switch to cast to the data type that the data was in, but it does work.我必须使用开关转换为数据所在的数据类型,但它确实有效。

public RowDataCollection SelectRow(string colName, object value) {
  if (!String.IsNullOrEmpty(colName) && (value != null) && (0 < Rows.Count)) {
    switch (Rows[0][colName].GetValueType()) {
      case TableDataType.Boolean:
        return new RowDataCollection(Rows.Where(r => (bool)r[colName].Value == (bool)value).ToList());
      case TableDataType.Character:
        return new RowDataCollection(Rows.Where(r => (char)r[colName].Value == (char)value).ToList());
      case TableDataType.DateTime:
        return new RowDataCollection(Rows.Where(r => (DateTime)r[colName].Value == (DateTime)value).ToList());
      case TableDataType.Decimal:
        return new RowDataCollection(Rows.Where(r => (Decimal)r[colName].Value == (Decimal)value).ToList());
      case TableDataType.Integer:
        return new RowDataCollection(Rows.Where(r => (int)r[colName].Value == (int)value).ToList());
      case TableDataType.String:
        return new RowDataCollection(Rows.Where(r => r[colName].Value.ToString() == value.ToString()).ToList());
    }
  }
  return null;
}

[Solved (short version)] [已解决(短版)]

Jon Skeet posted this about the same time I posted my solution, and (as always) his code is much nicer. Jon Skeet 大约在我发布我的解决方案的同时发布了这个,并且(一如既往)他的代码更好。

public RowDataCollection SelectRow(string colName, object value) {
  List<RowData> rowList = Rows.Where(r => r[colName].Value.Equals(value)).ToList();
  return new RowDataCollection(rowList);
}

@Jon Skeet: If I ever see your face in the same line at some software developer position I'm applying for, I'm just going to turn around and go home. @Jon Skeet:如果我在我申请的某个软件开发商 position 看到你的脸在同一行,我会转身和 go 回家。

@Everyone : Thanks for all the help! @Everyone :感谢所有帮助!

The result of a query like that isn't a List<T> , it's an IEnumerable<T> .这样的查询结果不是List<T> ,而是IEnumerable<T> If you want to convert that into a List<T> , just call ToList :如果要将其转换为List<T> ,只需调用ToList

List<RowData> rowList = (from item in Rows
                         where item[colName].Value == value
                         select item).ToList();

As it happens, you're only calling Where in your query.碰巧的是,您只是在查询中调用Where I would rewrite this as:我会将其重写为:

List<RowData> rowList = Rows.Where(item => item[colName].Value.Equals(value))
                            .ToList();

I'd also rename the method to something which is obviously filtering rather than projecting , given that the latter is the more common use of the term "select" in LINQ.我还将该方法重命名为明显过滤而不是投影的方法,因为后者是 LINQ 中“选择”一词的更常见用法。

As for input parameters - I suggest you validate the arguments and throw an exception if they're not valid:至于输入参数 - 我建议您验证 arguments 并在它们无效时抛出异常:

if (string.IsNullOrEmpty(colName))
{
    throw new ArgumentException("colName");
}

You can't directly cast an IEnumerable<RowData> to a List<RowData> , however, there does exist a convenience function Enumerable.ToList<T>() , used like so:您不能直接将IEnumerable<RowData>转换为List<RowData> ,但是,确实存在方便 function Enumerable.ToList<T>() ,使用如下:

List<RowData> rowList = (from item in Rows
                         where item[colName].Value == value
                         select item).ToList();

As for your second question, an exception would occur during the ToList() call as the LINQ expression is evaluated immediately.至于您的第二个问题,在ToList()调用期间会发生异常,因为会立即评估 LINQ 表达式。 You have a few options, including throwing ArgumentException s or returning an empty list.您有几个选择,包括抛出ArgumentException或返回一个空列表。 It depends on your use cases.这取决于您的用例。 I'd suggest simply throwing an exception (assuming you have some HasColumn() method on your RowData class):我建议简单地抛出一个异常(假设你的RowData类上有一些HasColumn()方法):

if (colName == null)
{
    throw new ArgumentNullException("colName");
}
else if (!Rows.All(row => row.HasColumn(colName)))
{
    throw new ArgumentException("No such column " + colName, "colName");
}

Per your edit, another approach, if a column missing is not necessarily a "problem":根据您的编辑,另一种方法,如果缺少列不一定是“问题”:

...
// note the change to Any()
else if (!Rows.Any(row => row.HasColumn(colName))
{
    throw new ArgumentException("No such column " + colName, "colName");
}

List<RowData> rowList = (from item in Rows
                         where item.HasColumn(colName)
                            && item[colName].Value == value
                         select item).ToList();

You're getting the error message because LINQ Queries return IEnumerable, not List.您收到错误消息是因为 LINQ 查询返回 IEnumerable,而不是 List。

If you need a List, it's easy enough:如果您需要一个列表,这很容易:

List<RowData> rowList = (from item in Rows
                         where item[colName].Value == value
                         select item).ToList();

You have to convert IQueriable<> to List<>, by calling ToList();您必须通过调用 ToList(); 将 IQueriable<> 转换为 List<>;

  public RowDataCollection Select(string colName, object value) {
      List<RowData> rowList = from item in Rows
             where item[colName].Value == value
             select item;
      return new RowDataCollection(rowList.ToList());
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM