Have you heard about extension methods yet? If you have then you probably know exactly what the title of this blog means. I can see this becoming one of the most asked about exceptions in the coming release. At least until the dust settles.
<Edit>
If you are running into the above exception, you can fix this without reading the entire post. Just add a "using System.Linq;" to your using block
if you are seeing the "cannot be inferred from the usage." exception mentioned below and you are trying to use Linq over DataSets you need to add a reference to System.Data.Entity. You will have to hunt for it under the 3.5 framework install directory.
</Edit>
So what is going on? Let’s write some code, a simple Linq over DataSets example that assumes you have the latest ctp installed.
using System;
using System.Data;
using System.Data.Common;
namespace ConsoleApplication3
{
class Program
static DataSet GetDataSet()
DataSet ds = new DataSet();
DataTable dt = new DataTable("Customer");
dt.Columns.Add("Name");
dt.Columns.Add("Country");
dt.Rows.Add(new string[] { "Name1", "Country1" });
dt.Rows.Add(new string[] { "Name2", "Country1" });
dt.Rows.Add(new string[] { "Name3", "Country3" });
ds.Tables.Add(dt);
return ds;
}
static void Main(string[] args)
DataSet ds = GetDataSet();
var query = ds.Tables["Customer"].AsEnumerable().Where(c => c.Field<string>("Country") == "Country1")
.Select(c => c.Field<string>("Name"));
foreach (string s in query)
Console.WriteLine(s);
For completeness sake I have added a very crude GetDataSet method, please excuse this code bloat but I hate code samples that are not self contained. Once we get a DataSet we do a very simple Linq query to return all the Names of customers living in Country1.
The code looks fairly reasonable, we hit compile and… Exception!:
'System.Data.DataTable' does not contain a definition for 'AsEnumerable' and no extension method 'AsEnumerable' accepting a first argument of type 'System.Data.DataTable' could be found (are you missing a using directive or an assembly reference?)
This is a fairly nice exception, readable text and it asks you whether you are missing a using or assembly reference (it turns out we are missing both). If you are reading this blog it is almost certain that you know exactly what the problem is, but let’s pretend that you don’t know what is going on here and do a quick “Microsoft live” search on the exception above. A quick search will almost certainly tell you that you are missing a “using System.Linq” statement. Let’s add this to our code above:
using System.Linq; //add this to the code above.
So, are we done? Not really, this is where things get interesting. When we go to compile the code we get the following gem:
The type arguments for method 'System.Linq.Enumerable.AsEnumerable<TSource>(System.Collections.Generic.IEnumerable<TSource>)' cannot be inferred from the usage. Try specifying the type arguments explicitly
This is a particularly useless exception. Not only does it make almost no sense, the suggestions is horrible (do not try to specify the type arguments explicitly). What went wrong?
The problem is that for the nice linq over DataSet code above to work we need to use the System.Data.Entity.dll EnumerableDataTable. To do this we need to add a reference to System.Data.Entity.dll in our project. Unfortunatelly there is no good way for System.Linq to throw a better exception here, it just can't know that you are trying to use the wrong AsEnumerable.
//Add System.Data.Entity.dll to the list of References of your project.
Finally your project will compile and run as expected, congratulations!
Ok, let’s go for some extra credit. Now that we have determined that we really needed to add the System.Data.Entity.dll reference why don’t we just remove the “using System.Linq” statement?
Very simple, because if we remove System.Linq we get the following exception:
'System.Collections.Generic.IEnumerable<System.Data.DataRow>' does not contain a definition for 'Where' and no extension method 'Where' accepting a first argument of type 'System.Collections.Generic.IEnumerable<System.Data.DataRow>' could be found (are you missing a using directive or an assembly reference?)
The reason for this is left as an exercise to the reader (I have always wanted to say that *grin*)
Rambling out