0

I am facing an issue while casting an API response type. The API returns List<object> in a particular format code given below

using System;
using System.Collections.Generic;       
        
public class Program
{
    public static void Main()
    {
        dynamic tupleStringList;
        tupleStringList = new List<dynamic>{Tuple.Create("a","b"),Tuple.Create("c","d")}; // this data will come API which I have no control
        IEnumerable<Tuple<string,string>> test = (IEnumerable<Tuple<string,string>>) tupleStringList;// here we need to cast as another internal function which use it as IEnumerable<Tuple<string,string>>
    }
}

The error I am getting is given below

Run-time exception (line 9): Unable to cast object of type 'System.Collections.Generic.List`1[System.Object]' to type 'System.Collections.Generic.IEnumerable`1[System.Tuple`2[System.String,System.String]]'.

Stack Trace:

[System.InvalidCastException: Unable to cast object of type 'System.Collections.Generic.List`1[System.Object]'`` to type 'System.Collections.Generic.IEnumerable`1[System.Tuple`2[System.String,System.String]]'.]  
   at CallSite.Target(Closure,CallSite,Object )  
   at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
   at Program.Main() :line 9
Dai
  • 141,631
  • 28
  • 261
  • 374
user3048027
  • 387
  • 1
  • 5
  • 24
  • Protip: don't use `dynamic` - nor `Tuple`. Is there a reason you're not using geneircs or `ValueTuple` instead? – Dai Sep 02 '22 at 14:03
  • _"The API returns `List` in a particular format code"_ - why isn't it returning something strongly-typed instead of resorting to boxing everything with `Object`? – Dai Sep 02 '22 at 14:05

1 Answers1

1

I suggest tupleStringList.Cast<Tuple<string, string>>(), maybe like:

(IEnumerable<Tuple<string, string>>)(tupleStringList.Cast<Tuple<string, string>>())

(This needs a using System.Linq; directive.)

Ralf has a point in the comments (see Extension method and dynamic object): If extensions methods are not considered for the binding of a dynamic expression, cast to nongeneric IEnumerable first. For example:

var tupleStringListCast = (IEnumerable)tupleStringList;
var test = tupleStringListCast.Cast<Tuple<string, string>>();

Or call Cast<TResult>() with usual static call syntax:

var test = (IEnumerable<Tuple<string, string>>)(Enumerable.Cast<Tuple<string, string>>(tupleStringList));

However, it assumes the pairs are really of type Tuple<,>.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
  • ... and tupleStringList not being a dynamic also ;) – Ralf Sep 02 '22 at 12:25
  • @Ralf `tupleStringList` _was_ declared `dynamic`? What do you mean? – Jeppe Stig Nielsen Sep 02 '22 at 12:26
  • In the author example tupleStringList is defined as dynamic. You will have a hard time calling Cast on a dynamic. So in the cast crazyness needed you need to also cast tupleStringList to an IEnumerable<> to be able to call Cast. – Ralf Sep 02 '22 at 13:06
  • 1
    @Ralf You can call anything on a `dynamic` at compile-time. Everything compiles. Because the _binding_ is postponed until the program runs (run-time). At that time, the extension method `.Cast()` will apply if only the actual run-time type of `tupleStringList` is something that implement nongeneric `IEnumerable`. This will likely be the case. Another question is if the instances yielded are exactly of type `Tuple`. Which is why I said "assumes" in my answer. The asker provided no details. – Jeppe Stig Nielsen Sep 02 '22 at 13:13
  • Interestingly Net 5 has a problem with finding the Cast method (RuntimeBinderException) while Net 6 has not as i thought. But your correct on that we are missing context for a "perfectly" fitting answer. – Ralf Sep 02 '22 at 13:25
  • @Ralf You were more correct than I thought initially. I have updated my answer. Thanks. – Jeppe Stig Nielsen Sep 02 '22 at 13:36