rds80
rds80

Reputation: 629

DataTable type arguments cannot be inferred

In the code below, I'm adding a parameterValue for each row in the parameters datatable.

However, I'm getting the following error:

"The type arguments for method 'EnumerableRowCollectionExtensions.Select(EnumerableRowCollection, Func)' cannot be inferred from the usage. Try specifying the type arguments explicitly."

Can someone help me understand what type argument I need to explicitly define in the code?

Here is the code with the error:

parameters.AsEnumerable().Select(x => 
{
    ParameterValue parameterValue = new ParameterValue();
    parameterValue.Name = x["name"].ToString();
    parameterValue.Value = x["value"].ToString();
    parameterList.Add(parameterValue);
 });

This works fine in a foreach loop. Here is the code for that:

foreach (DataRow row in parameters.Rows)
{
   ParameterValue parameterValue = new ParameterValue();
   parameterValue.Name = row["name"].ToString();
   parameterValue.Value = row["value"].ToString();

   parameterList.Add(parameterValue);
}

Upvotes: 1

Views: 1079

Answers (2)

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236288

Enumerable.Select is a projection method. It projects each input item of type TSource into the new form of type TResult. Thus it accepts a selector delegate which does this TSource > TResult projection. Your selector delegate looks like this:

x => 
{
    ParameterValue parameterValue = new ParameterValue();
    parameterValue.Name = x["name"].ToString();
    parameterValue.Value = x["value"].ToString();
    parameterList.Add(parameterValue);
}

I.e. it takes DataRow as TSource and projects it to.. nothing. You do not return any value from this delegate. Thus compiler cannot understand which TResult it should use.

Now solution. Actually, you want to do two actions here:

  • project each row to ParameterValue
  • add each projected value to the list (new or existing)

First part is projection. Just use delegate which takes a DataRow as TSource and returns ParameterValue as TResult:

x => new ParameterValue{ Name = x.Field<string>("name"), Value = x.Field<string>("value") }

The second part can be done in two ways. You can create a new list from all parameter values. This is a declarative style of programming - instead of specifying how to add values to list you just say 'I want list':

var parameterList = parameters.AsEnumerable()
      .Select(r => new ParameterValue { 
          Name = r.Field<string>("name"), // note this LINQ to DataSet syntax
          Value = r.Field<string>("value")
      }).ToList();

Or you can use a simple foreach loop to add each projected value one by one to existing list. But here I would use query syntax for projection:

var parameterValues = from r in parameters.AsEnumerable()
                      select new ParameterValue { 
                          Name = r.Field<string>("name"),
                          Value = r.Field<string>("value")
                      };

foreach(var parameterValue in parameterValues)
    parameterList.Add(parameterValue);

Upvotes: 1

fubo
fubo

Reputation: 45997

The correct syntax of

parameters.AsEnumerable().Select(x => 
{
    ParameterValue parameterValue = new ParameterValue();
    parameterValue.Name = x["name"].ToString();
    parameterValue.Value = x["value"].ToString();
    parameterList.Add(parameterValue);
 });

is

parameterList.AddRange(parameters.AsEnumerable().Select(x =>            
    new ParameterValue()
    {
        Name = x["name"].ToString(),
        Value = x["value"].ToString()
    }));

Side note: instead of x["name"].ToString() you should access the field by its type x.Field<string>("name")

Upvotes: 3

Related Questions