C # - LINQ select from collection

I am trying to write a simple Select method for a class that inherits from IList .

 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 that I have are:

At first:

  • VS2010 Cannot implicitly convert type 'IEnumerable<RowData>' to 'List<RowData>'. An explicit conversion exists (are you missing a cast?) reports 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?)

Alright, where does the CAST go?

Second:

  • Someone might pass an invalid colName (i.e. String.IsNullOrEmpty(colName) ) or a null parameter (object value == null) .

How can I handle the way my function returns if the input parameters are invalid?

[solvable]

I edited the Select statement (even renamed it in the sentences here). I had to use a switch to transfer to the data type that the data was in, but it works.

 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; } 

[Allowed (short version)]

Jon Skeet posted this around the same time that I posted my solution, and (as always) its code is much nicer.

 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 on the same line at some position of the software developer Iโ€™m applying for, I'm just going to turn around and go home.

@ Total: Thanks for the help!

+8
c # linq visual-studio-2010
source share
4 answers

The result of such a query is not List<T> , but IEnumerable<T> . If you want to convert it to List<T> , just call ToList :

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

As it happens, you only call Where in your request. I would rewrite this as:

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

I would also rename this method to something that would obviously filter rather than project, given that the latter is a more common use of the term "select" in LINQ.

As for the input parameters - I suggest you check the arguments and throw an exception if they are invalid:

 if (string.IsNullOrEmpty(colName)) { throw new ArgumentException("colName"); } 
+10
source share

You cannot directly convert IEnumerable<RowData> to List<RowData> , however there is a convenient function Enumerable.ToList<T>() used like this:

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

As for your second question, an exception is thrown during the call to ToList() , since the LINQ expression will be evaluated immediately. You have several options, including throwing an ArgumentException or returning an empty list. It depends on your use cases. I would suggest just throwing an exception (assuming you have a HasColumn() method in your RowData class):

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

In your editing, another approach, if the missing column 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(); 
+1
source share

You get an error because LINQ queries return IEnumerable, not List.

If you need a list, it is quite simple:

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

You need to convert IQueriable <> to List <> by calling ToList ();

  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()); } 
-one
source share

All Articles