Converting dynamic to object
Asked Answered
R

3

7

Here is my code:

MyClass here = new MyClass();
IEnumerable<MyClass> vats = (IEnumerable<MyClass>)here.All();

The All() method returns IEnumerable<dynamic>. I want to convert it to IEnumerable<MyClass>. The line above doesn;t work, it says Unable to cast object of type 'd__15' to type 'System.Collections.Generic.IEnumerable`1[MyClass]'.

I also tried:

 IEnumerable<MyClass> vats = here.All() as IEnumerable<MyClass>;

but it returns null.

Redundancy answered 7/5, 2012 at 6:45 Comment(2)
@Tigran Here it is. Look at the Massive.cs file. github.com/robconery/massiveRedundancy
Any reason you can't keep it "dynamic" in your code?Furfuraceous
E
6

Similar to dbaseman's answer (and AKX's comment) I'd use Cast:

IEnumerable<MyClass> vats = here.All().Cast<MyClass>();

You'll need a using directive for LINQ though:

using System.Linq;

at the top of your file. It sounds like you haven't got that if the Select method isn't recognized.

Note that this assumes that each value really is a MyClass reference.

EDIT: If you want to be able to access the values by index, I'd recommend using ToList:

List<MyClass> vats = here.All().Cast<MyClass>().ToList();

While ToArray would work too, I personally favour lists over arrays in most cases, as they're rather more flexible.

EDIT: It sounds like your results are actually full of ExpandoObject. You'll need to create a new instance of MyClass from each item, e.g.

List<MyClass> vats = here.All()
                         .Select(item => new MyClass(item.Name, item.Value))
                         .ToList();

or possibly:

List<MyClass> vats = here.All()
                         .Select(item => new MyClass {
                                     Name = item.Name,
                                     Value = item.Value,
                                 })
                         .ToList();

That's just an example, which I wouldn't expect to work straight away - we can't do any better than that as we know nothing about how your results are actually being returned.

It does sound like you're in over your head here, I'm afraid.

Earlie answered 7/5, 2012 at 6:56 Comment(11)
And where to look for my values?Like vats[0], vats[1]. To the result here.All() I could access those values like thatRedundancy
@srcee if you wish to have an indexer (instead of iterating the entire list) you'd need to appen .ToArray() after the call to selectFelty
@Srcee: You can iterate over your values from just a sequence, but if you want an indexer you'll need a list or an array. But it sounds like you're quite new to C# and LINQ - in which case I would suggest you stay away from dynamic typing for a while if you can... it's going to make it harder to understand the basics...Earlie
I believe your last point could use either sample code or elaboration. I feel that if one already knows the difference one would understand your point but for those unaware that (T)obj can be both a cast and a conversion it migh not be so eisily understoodFelty
@RuneFS: It gets even worse when dynamic typing is involved - but given the other comments, I suspect it's actually best not to go into that in this particular case... as I suspect it would confuse the OP further.Earlie
@JonSkeet I get error Cannot convert type 'System.Dynamic.ExpandoObject' to 'MyClassRedundancy
interesting point with using ToList instead of ToArray I suggested ToArray for exactly the same reason (list's being more flexible) and seeing that OP was only asking for an indexer. I could also see the point in not elaborating because it was basically OT.Felty
@RuneFS: Why would you use ToArray because lists are more flexible? Both offer indexers, List<T> then allows the OP to add extra elements later etc... what downside do you see for lists? I would generally suggest steering clear of arrays where possible.Earlie
Actually I would have preferred an immutable list. I generally steer for the narrowest interface possible. (in this particular case as I noted I deviate from that and would normally choose list though it's an odd choice seeing that I seldom would add anything to it).Felty
@RuneFS: It's also more efficient to convert to a list than to an array, as you don't need to end up with an array of exactly the right size at the end :) You can then wrap either an list or an array as an immutable list, of course.Earlie
I believe the efficiency can be neglected since the worst case is having to release the extra allocated space (which can be neglected when using lists). I don't disagrre with anything you said. I simply find it interesting that based on the same arguments but valuing different aspects differently lands us in opposite camps. You obviously value flexibility for the future higher than keeping the interfaces narrow and I try to keep the interfaces my code depend on as narrow as I reasonably can and doesn't really worry about flexibility I don't need now (or expect to have to use in the near futureFelty
K
1

You just have to cast each individual object:

MyClass[] vats = here.All().Select(item => (MyClass)(dynamic)item).ToArray();
Katinakatine answered 7/5, 2012 at 6:50 Comment(11)
@Scree I don't follow. Which values?Katinakatine
@dbaseman Like vats[0], vats[1]. To the result here.All() I could access those values like that.Redundancy
@AKX it depends on whether it's a custom conversion or a upcast/downcast. the latter works in both cases the former only in the version posted hereFelty
@Scree edited again. I think that's what you're looking for-- to use the bracket notation it has to be an array or list.Katinakatine
@dbaseman I get error Cannot convert type 'System.Dynamic.ExpandoObject' to 'MyClass'Redundancy
@Scree Oh... it's an ExpandoObject. I edited my answer once more, that one should work. :PKatinakatine
@Scree consider me stumped. I'm able to cast from ExpandoObject using that code.Katinakatine
@Srcee: How do you expect to build a MyClass from an ExpandoObject? We don't know anything about how your data is being returned.Earlie
@JonSkeet You have the All() method in the link above.Redundancy
@Srcee: We've got no idea what MyClass is though, or what properties you want to copy from the results.Earlie
@Srcee: Also, it's worth editing vital information into the question, instead of making people read all the comments... Please read tinyurl.com/so-hintsEarlie
F
0

The first thing to work out before you can create a solution is what types the objects will have at run time. Seeing from your comments that they are going to be ExpandoObjects and assuming MyClass does not derive from ExpandoObject you can't use the .Cast<T> method since it only supports casts and not custom conversions.

There's a trick you can use to convert from ExpandoObjects using the JavaScriptSerializer

taking from this link here an extension method that you could use

public static IEnumerable<T> Convert<T>(this IEnumerable<dynamic> self){
    var jsSerializer = new JavaScriptSerializer();
    foreach(var obj in self){
        yield return jsSerializer.ConvertToType<T>(obj);
    }
}

in your case then all you have to do is change the Cast in skeets answer to Convert.

List<MyClass> vats = here.All().Convert<MyClass>().ToList();

This is a bit hackish since the JavaScriptSerializer was not meant to do this but it does solve the problem.

Felty answered 7/5, 2012 at 7:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.