3

I have the below code:

List<Type> p1 = new List<Type>();
p1.Add(typeof(int));
p1.Add(typeof(string));
dynamic genericDic = typeof(Dictionary<, >);
dynamic specificDic1 = genericDic.MakeGenericType(p1.ToArray());
dynamic dic1 = Activator.CreateInstance(specificDic1);
dic1.Add(1, "John");
dic1.Add(2, "Smith");
dynamic genericLst = typeof(List<>);
dynamic specificLst = genericLst.MakeGenericType(typeof(string));
dynamic list = Activator.CreateInstance(specificLst);
list.AddRange(dic1.Values.ToList());

When i try to perform the list.AddRange(dic1.Values.ToList()); i get the following exception

Public member 'ToList' on type 'ValueCollection' not found.

Stack trace:

   at Microsoft.VisualBasic.CompilerServices.Symbols.Container.GetMembers(String& MemberName, Boolean ReportErrors)
   at Microsoft.VisualBasic.CompilerServices.NewLateBinding.ObjectLateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack)
   at Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack)
   at StyleResearch.DataManagement.DataStream.Business.MonthEndProcess.ConverToLegacyStructureInMemory(List`1 marketDataTypeIds, String tableName, Int32 placeHolderValue) in C:\Style Research\Work\SRDM\trunk\StyleResearch.DataManagement.DataStream.Business\MonthEndProcess.vb:line 1850
   at StyleResearch.DataManagement.DataStream.UI.DDLMonthEndProcess._Lambda$__6(LegacyStructureDetail legacy) in C:\Style Research\Work\SRDM\trunk\StyleResearch.DataManagement.DataStream.UI\DDLMonthEndProcess.vb:line 1198
   at System.Threading.Tasks.Parallel.<>c__DisplayClass2d`2.<ForEachWorker>b__23(Int32 i)
   at System.Threading.Tasks.Parallel.<>c__DisplayClassf`1.<ForWorker>b__c()

NOTE: I have converted by VB.NET sample to C# but the stack trace is from the VB.NET project

When i do the below it works absolutely fine:

Dictionary<int, string> dic = new Dictionary<int, string>();
dic.Add(1, "John");
dic.Add(2, "Smith");
List<string> lst = new List<string>();
lst.AddRange(dic.Values.ToList());
abatishchev
  • 98,240
  • 88
  • 296
  • 433
Rajesh
  • 7,766
  • 5
  • 22
  • 35

4 Answers4

3

Just cast it:

list.AddRange(((IEnumerable<string>)dic1.Values).ToList());

Also, you can go via dynamic again:

list.AddRange((dynamic)dic1.Values));
Dave Bish
  • 19,263
  • 7
  • 46
  • 63
  • As i understand the idea behind using dynamics and reflections is that you dont know type of elements in list at compile time (IEnumerable) so you can not just cast to it at compile time. Overwise you can just use types list without reflection and dynamics – Nikolay Jul 05 '12 at 11:10
  • Agreed - but he's already declaring the type above - so, in this instance it's known. – Dave Bish Jul 05 '12 at 15:32
2

ToList<T>() is an extension method to IEnumerable<T>. But your dic1.Values is of dynamic type not IENumerable<string> so .Net can not find and use this extension method. You can try just simple foreach:

foreach (var value in dic1.Values)
  list.Add(value)
Nikolay
  • 3,658
  • 1
  • 24
  • 25
  • Thanks for the reply, but I do know that approach.Keen to know why it fails when i create objects using reflection and not when doing it normally. – Rajesh Jul 05 '12 at 10:44
  • 2
    As i said that happens because of dynamic type and extension method (ToList). Extension methods are not supported for dynamics (http://stackoverflow.com/questions/5311465/extension-method-and-dynamic-object-in-c-sharp) – Nikolay Jul 05 '12 at 10:46
0
list.AddRange((IEnumerable<string>)dic.Values))

or

List<string> list = ((IEnumerable<string>)dic.Values).ToList();

or

List<string> list = new List<string>((IEnumerable<string>)dic.Values);
abatishchev
  • 98,240
  • 88
  • 296
  • 433
  • When i use the above code i get this exception: Public member 'Cast' on type 'ValueCollection' not found. – Rajesh Jul 05 '12 at 10:47
  • None of those work: 'System.Collections.Generic.Dictionary.ValueCollection' does not contain a definition for 'Cast' – Dave Bish Jul 05 '12 at 10:49
  • 1
    @Rajesh: Then try `System.Linq.Enumerable.Cast(input)` – abatishchev Jul 05 '12 at 10:49
  • Also - this is worse than casting the whole collection to IEnumerable - as it will attempt to cast each element in the collection to 'string' - not cast the whole collection to an Enumerable type. – Dave Bish Jul 05 '12 at 10:50
0

Try calling without extension function syntax, i.e. something like

Enumerable.ToList ( (dynamic) dic1.Values )

The DLR does not search for extension functions of inherited interfaces at runtime (for performance reasons or to avoid ambiguities, I guess).

JohnB
  • 13,315
  • 4
  • 38
  • 65