We help IT Professionals succeed at work.

LINQ query set as a method return

Kozela
Kozela used Ask the Experts™
on
Hello Everyone,

How do I return the values from a LINQ qurery as a method return?

In other words if I have a LINQ Query

var query ...

and I want to return a list as

query.ToList();

in a method such as

public List getResults(){

   var query ....

   return query.ToList();  or even query.ToArray

}

I have the query, I just don't know how to return the dataset to the caller.

Thanks

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
You could return System.Collections.Generic.IEnumerable<{Type}> which is what comes back from the linq query.

If you really wanted to convert it to a list then use:
List<{Type}> myListToReturn = myQueryResult.ToList<{Type}>();

and make your return type from your getResults funtion be List<{Type}>

if you dont know the type you could use generic typing with your getResults function (so you would then return List<T>.

For generic info see http://msdn.microsoft.com/en-us/library/ms379564(VS.80).aspx

Author

Commented:
dave4dl thanks for getting back to me so quickly.  I tried that and I get the following error:

System.Collections.Generic.IEnumerable<AnonymousType#1>' does not contain a definition for 'ToList' and the best extension method overload 'System.Linq.Enumerable.ToList<TSource>(System.Collections.Generic.IEnumerable<TSource>)' has some invalid arguments

Any ideas??

Thanks again

Author

Commented:
Sorry.  Forgot this.

This is the line of code I tried when I received the error in my previous post.

List<string> items = query.ToList<string>();

Thanks
Adam MenkesC# ASP.NET Developer
Top Expert 2010

Commented:
Make the return type IList (the interface, instead of a class)


private IList test()
        {
            List<string> somelist = new List<string> {"test"};
            return (from s in somelist
                    select s).ToList();
        }

Open in new window

Author

Commented:
amenkes, thanks for the feed back.

I just tried returning the IList and I get the following error:

Using the generic type 'System.Collections.Generic.IList<T>' requires '1' type arguments

What am I missing here?

Thanks
Top Expert 2009

Commented:
Kozela,

You can return a strongly typed list from your LINQ. Have a look at the following example:


List<Employee> employees = new List<Employee>();
employees.Add(new Employee() { FirstName = "A", LastName = "E" });
employees.Add(new Employee() { FirstName = "B", LastName = "D" });
employees.Add(new Employee() { FirstName = "C", LastName = "C" });
employees.Add(new Employee() { FirstName = "D", LastName = "B" });
employees.Add(new Employee() { FirstName = "E", LastName = "A" });

var result = (from e in employees
             select new Employee
                        {
                            FirstName = e.FirstName,
                            LastName = e.LastName
                        }).ToList();

for (int i = 0; i < result.Count; i++)
{
    Console.WriteLine(result[i].FirstName);
    Console.WriteLine(result[i].LastName);
}

Open in new window

Top Expert 2009

Commented:
Sorry, here's a better example. I just created a class called Employee and added some dummy data (just to create a collection and run a LINQ against). In my query, I'm eliminating one record and returning List<Employee> to the calling method.

This works just fine. You might want to do something like this.

List<Employee> employees = GetEmployees();

    for (int i = 0; i < employees.Count; i++)
    {
        Console.WriteLine(employees[i].FirstName + " " + employees[i].LastName);
    }
    Console.ReadLine();
}

private static List<Employee> GetEmployees()
{
    List<Employee> employees = new List<Employee>();
    employees.Add(new Employee() { FirstName = "A", LastName = "E" });
    employees.Add(new Employee() { FirstName = "B", LastName = "D" });
    employees.Add(new Employee() { FirstName = "C", LastName = "C" });
    employees.Add(new Employee() { FirstName = "D", LastName = "B" });
    employees.Add(new Employee() { FirstName = "E", LastName = "A" });

    var result = (from e in employees
                  where e.FirstName != "A"
                  select new Employee
                  {
                      FirstName = e.FirstName,
                      LastName = e.LastName
                  }).ToList();
    return result;
}

Open in new window

Adam MenkesC# ASP.NET Developer
Top Expert 2010
Commented:
Use the return type as IList in your function declaration:

public IList getResults(){
  var query ....
  return query.ToList();  
}

This way, you don't need to set it as

public List<specific type> getResults()

Author

Commented:
amenkes. Maybe this will be easier:
I am getting the follwoing:
Using the generic type 'System.Collections.Generic.IList<T>' requires '1' type arguments
 when I try to retirn the IList
Here is my LINQ query and how I am trying to return it.


String compNum = "99";

var query = (from
cPr in Prod.Descendants("product")

where cPr.Element("company").Value == compNum

orderby cPr.Attribute("code").Value

select

new
{
productNum = cPr.Attribute("code").Value

});

return query.ToList();
 
Thanks.
Adam MenkesC# ASP.NET Developer
Top Expert 2010

Commented:
Basically, one part of your code has the variable:

IList mylist = getResults();

and your method:

public IList getResults() {
string compnum = "99";
return (from cPr in Prod.Descendants("product")
        where cPr.Element("company").Value == compNum
        orderby cPr.Attribute("code").Value
        select new
        {
          productNum = cPr.Attribute("code").Value

        }).ToList();
}
Fernando SotoRetired
Distinguished Expert 2017

Commented:
Hi Kozela;

The code in the code snippet below should do what you want.

Fernando
String compNum = "99";
...

public List<String> getResults()
{
    List<String> query = (from cPr in Prod.Descendants("product")
                          where cPr.Element("company").Value == compNum
                          orderby cPr.Attribute("code").Value
                          select cPr.Attribute("code").Value);

    return query.ToList();
}

Open in new window

Kozela,

Apparently IEnumerable's ToList function cannot handle a list of the type you are passing it.  The workaround is to build your own function to do it (this is pretty easy to do).  

This function would take an IEnumerable parameter and return a list of the type you are working with (or you  could make it generic).  For each item in the ienumerable parameter, add that item to the new list object you have created (that list object is what you will return from this new function).

Author

Commented:
Thanks Fernando.

I tried that earlier and I get the following compiler error:

Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<string>' to 'System.Collections.Generic.List<string>'. An explicit conversion exists (are you missing a cast?)

amenkes.  Thanks.  I have that part.  However, I am still getting that funny error on the compiler.

Using the generic type 'System.Collections.Generic.IList<T>' requires '1' type arguments

Thanks again to both of you.

Author

Commented:
dave4dl: Thanks.

That is the only way I have been able to get the data out of the method.  It seems somewhat inefficient to roll the Linq results into another data structure to get it out.  I have been trying to find a more straight forward approach to solve this and streamline the process.

Thanks for the feedback.

Fernando SotoRetired
Distinguished Expert 2017

Commented:
Hi Kozela;

Are you sure your select statement looks like this:

select cPr.Attribute("code").Value

and NOT like this

select new
{
    productNum = cPr.Attribute("code").Value
}

If so please post the actual code from your program here.

Fernando
Adam MenkesC# ASP.NET Developer
Top Expert 2010

Commented:
>>t seems somewhat inefficient to roll the Linq results into another data structure to get it out.<<
You don't need to do this. I thought you were using this just for learning purposes, using a simple example.

For example, you could do a
            return (from c in Something
                    where c.Id == someID
                    select c).FirstOrDefault();

And this would get the whole record / object.
Once you cast it to the appropriate type, you can access all of the data.

And if you had instead used a strongly typed object instead of the interface
List<mytype> mylist = getResults();
Now, for each mylist item, you could check the .Attribute

Author

Commented:
Fernando,  This is the Linq query

public List<String> prodList()
{
List<String> query = (from cPr in Prod.Descendants("product")
                      where cPr.Element("company").Value == compNum
                      orderby cPr.Attribute("code").Value
                      select cPr.Attribute("code").Value);
return query.ToList();
}
Adam MenkesC# ASP.NET Developer
Top Expert 2010

Commented:
Can you post your code and what you are trying to do?

Are you trying to keep things flexible and not have the function strongly typed (using the IList interface) or are you trying to work with a specific type, and is it a type that supports IEnumerable or is it your own class?

Where does Prod.Descendants get defined? Are you using an ORM such as Entity Frameworks, nHibernate, etc?

Fernando SotoRetired
Distinguished Expert 2017

Commented:
Hi Kozela;

Can you please post the XML document you are using because the query looks like it should work,

Thank you
Fernando

Author

Commented:
Fernando,

Here is a small snippet.  The file is about 6Megs.

<prod>
      <product code="450" description="XML Substrate">
            <company>99</company>
      </product>
      <product code="206" description="CFG Substrate">
            <company>99</company>
            <company>105</company>
            <company>253</company>
      </product>
</prod>

thanks

Author

Commented:
amenkes,

This is a LINQ to XML query.  The data is coming from an XML file I receive rom a third party.  I am parsing out the data so that I can determine the products that are being provided by a given company.

I am trying to use the data as a data source for a control.  So the idea is that I call the method, get a List or and Array back to populate the control.  In theory, i should be able to get a List of strings or a Array of Strings.  But I cant seem to do that directly by returning a Linq dataset.

Thanks again for you help and expertise.


Fernando SotoRetired
Distinguished Expert 2017

Commented:
This is the corrected working code

public List<String> prodList()
{
    XDocument Prod = XDocument.Load("TestData.xml");
    String compNum = "99";

    List<String> query = (from cPr in Prod.Descendants("product")
                          where cPr.Element("company").Value == compNum
                          orderby cPr.Attribute("code").Value
                          select cPr.Attribute("code").Value).ToList();

    return query;
}

Fernando
Retired
Distinguished Expert 2017
Commented:
Hi Kozela;

Sorry I should have read the error message more closely, "Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<string>'  to 'System.Collections.Generic.List<string>', the query was returning this, System.Collections.Generic.IEnumerable<string>, This is due to the fact that Linq to XML returns the type of IEnumerable and because the select is returning a string a IEnumerable<String>. To return a List<String> which is the type of the receiving variable you need to convert the result of the query to List<String> before storing it in the variable query by passing the IEnumerable<string> to the ToList() method.

Fernando

Author

Commented:
That did it!  

That is what I was missing

Thank so much for the help.
Fernando SotoRetired
Distinguished Expert 2017

Commented:
Not a problem, glad I was able to help.  ;=)