error CS1977: Cannot use a lambda expression as an argument to a dynamically dispatched operation
Asked Answered
C

3

6

I've converted some code from vb.net to c# but it's having problems with a lambda.

error CS1977: Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type.

Here's the translated code..

dynamic ds = (JArray)o["Tables"][0]["Rows"];
using(var connection = new SqlConnection(cnnString))
    {connection.Open();
     ds.Select(ja =>
        connection.Execute("INSERT INTO dbo.AddPlay(UserId, Timestamp, YoutubeId, Source, PlayCount, Rating) " + 
                " VALUES(ja(0).Value<string>(), ja(1).Value<string>() ja(2).Value<string>(), ja(3).Value<string>(), GetInt(ja(4)), GetInt(ja(5)))"));
    }
Chuipek answered 24/7, 2017 at 15:52 Comment(3)
Your code has a problem - did you really mean to insert the string "ja(0).Value<string>()" into your database? Also, you should be using parameters and not string substitution. Finally, Select() isn't for replacing a foreach loop.Interlanguage
oh no. Well spotted ! I have the double disadvantage of being a VB.net programmer trying to convert my VB code to C# in an Azure Function App that has no Intellisense. Why is using Select() wrong to use to loop my JArray ?Chuipek
The signature of Select is public static IEnumerable<TResult> Select<TSource, TResult>( this IEnumerable<TSource> source, Func<TSource, TResult> selector ). If you aren't using/needing the result IEnumerable<TResult> then it is probably the wrong operation.Interlanguage
I
3

Using a foreach and creating a parameterized SqlCommand is best practice

var ds = (JArray)o["Tables"][0]["Rows"];

using (var connection = new SqlConnection(cnnString)) {
    connection.Open();
    var cmdIns = new SqlCommand("INSERT INTO dbo.AddPlay(UserId, Timestamp, YoutubeId, Source, PlayCount, Rating) VALUES(@UserId, @Timestamp, @YoutubeId, @Source, @PlayCount, @Rating)", connection);
    cmdIns.Parameters.Add("@UserId", SqlDbType.VarChar, 20);
    cmdIns.Parameters.Add("@Timestamp", SqlDbType.VarChar, 20);
    cmdIns.Parameters.Add("@YoutubeId", SqlDbType.VarChar, 20);
    cmdIns.Parameters.Add("@Source", SqlDbType.VarChar, 20);
    cmdIns.Parameters.Add("@PlayCount", SqlDbType.Int);
    cmdIns.Parameters.Add("@Rating", SqlDbType.Int);

    foreach (var ja in ds) {
        cmdIns.Parameters["@UserId"].Value = ja[0].Value<string>();
        cmdIns.Parameters["@Timestamp"].Value = ja[1].Value<string>();
        cmdIns.Parameters["@YoutubeId"].Value = ja[2].Value<string>();
        cmdIns.Parameters["@Source"].Value = ja[3].Value<string>();
        cmdIns.Parameters["@PlayCount"].Value = GetInt(ja[4]);
        cmdIns.Parameters["@Rating"].Value = GetInt(ja[5]);

        cmdIns.ExecuteNonQuery();
    }
}
Interlanguage answered 24/7, 2017 at 17:32 Comment(2)
That worked with a little tweek. The cmdIns.Parameters["@UserId"] = ja(0).Value<string>(); should read cmdIns.Parameters["@UserId"].Value = ja[0].Value<string>();Chuipek
Interesting. I guess I didn't have enough data types to get a type error.Interlanguage
G
3

dynamic causes the variable type to be determined at runtime rather than compile time, which doesn't play well with lambda expressions. But you don't need a dynamic variable here; you already know the type is JArray because you are doing a cast. So change the variable declaration from dynamic to JArray and that will fix the compiler error:

JArray ds = (JArray)o["Tables"][0]["Rows"];

Your code has other problems however:

  • SqlConnection does not contain an Execute method. You need to create a SqlCommand and use its ExecuteNonQuery method to do the insert.
  • Your SQL will not work as intended because you are not actually placing the values of the JArray into the command string. You should be using SQL parameters anyhow.

See @NetMage's answer to see how to fix these issues.

Ghyll answered 24/7, 2017 at 16:42 Comment(0)
I
3

Using a foreach and creating a parameterized SqlCommand is best practice

var ds = (JArray)o["Tables"][0]["Rows"];

using (var connection = new SqlConnection(cnnString)) {
    connection.Open();
    var cmdIns = new SqlCommand("INSERT INTO dbo.AddPlay(UserId, Timestamp, YoutubeId, Source, PlayCount, Rating) VALUES(@UserId, @Timestamp, @YoutubeId, @Source, @PlayCount, @Rating)", connection);
    cmdIns.Parameters.Add("@UserId", SqlDbType.VarChar, 20);
    cmdIns.Parameters.Add("@Timestamp", SqlDbType.VarChar, 20);
    cmdIns.Parameters.Add("@YoutubeId", SqlDbType.VarChar, 20);
    cmdIns.Parameters.Add("@Source", SqlDbType.VarChar, 20);
    cmdIns.Parameters.Add("@PlayCount", SqlDbType.Int);
    cmdIns.Parameters.Add("@Rating", SqlDbType.Int);

    foreach (var ja in ds) {
        cmdIns.Parameters["@UserId"].Value = ja[0].Value<string>();
        cmdIns.Parameters["@Timestamp"].Value = ja[1].Value<string>();
        cmdIns.Parameters["@YoutubeId"].Value = ja[2].Value<string>();
        cmdIns.Parameters["@Source"].Value = ja[3].Value<string>();
        cmdIns.Parameters["@PlayCount"].Value = GetInt(ja[4]);
        cmdIns.Parameters["@Rating"].Value = GetInt(ja[5]);

        cmdIns.ExecuteNonQuery();
    }
}
Interlanguage answered 24/7, 2017 at 17:32 Comment(2)
That worked with a little tweek. The cmdIns.Parameters["@UserId"] = ja(0).Value<string>(); should read cmdIns.Parameters["@UserId"].Value = ja[0].Value<string>();Chuipek
Interesting. I guess I didn't have enough data types to get a type error.Interlanguage
C
0

While the other answer work specific for this case, and is even preferred, this works in general for a CS1977:

Add a cast in the lambda,

From this:

ds.Select(ja => ...);

To this:

ds.Select((Func<object, object>) (ja => ...));

I assumed that Func<object, object> is correct here the correct type

Clipper answered 19/9, 2024 at 21:51 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.