Converting dynamic to object - c#

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.

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.

You just have to cast each individual object:
MyClass[] vats = here.All().Select(item => (MyClass)(dynamic)item).ToArray();

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.

Related

Adding to a mutable type as if it was immutable (orderlessly)

I'm building an object on form:
return table.Rows.Cast<DataRow>()
.Select(row => new Something
{
Field = row["field1"] as int?,
Bunch = GetBunch(index)
});
with GetBunch() as follows.
private IList GetBunch(int index) { ... }
It works as supposed to. Now, we've noticed that we need to add an additional element to the array that we put into Bunch. For a range of reasons, it's not an option to change the signature of the method, nor is it feasible to add the extra element inside it.
I tried to add the extra thingy like so:
return table.Rows.Cast<DataRow>()
.Select(row => new Something
{
Field = row["field1"] as int?,
Bunch = GetBunch(index).Add(new Thingy() { ... })
});
but it didn't work because Add() doesn't return the original array with the new element in it. It returns an int. If the original object would be immutable, the result of Add() would be what I wish but, apparently, it isn't.
Is it possible to immutabilize an mutable object? If not (because I'm fairly certain it's not), how can I handle this easily? (Easily = without storing the created thing and then accessing it and adding an element to Bunch property's array.)
NB, the order of the result is of no importance in this case. The proper type would be Bag of some kind but I'm hand-tied by the pre-existing design.
Something like this maybe:
return table.Rows.Cast<DataRow>()
.Select(row => {
var list = GetBunch(index);
list.Add(new Thingy() { ... });
return new SomeThing
{
Field = row["field1"] as int?,
Bunch = list
};
});
As #Chris noted in the comments you can use a lambda statement, you don't necessarily need to use lamda expression.You can do whatever you want inside of the blocks since it's just a method that takes a DataRow and returns SomeThing.
Alternative to good Selman22's answer: create helper extension method that would let you add to result of GetBunch() without need to wrap it in lambda inline:
static class MyListExtenstions
{
static IList AddToList<T>(this IList list, T item)
{
list.Add(item);
return list;
}
}
And use it inline:
return table.Rows.Cast<DataRow>()
.Select(row => new Something
{
Field = row["field1"] as int?,
Bunch = GetBunch(index).AddToList(new Thingy() { ... })
});
One more LINQ approach that creates more intermediate objects, but would work on immutable (meaning adding items throws exception) list:
If you want to have method that can be used for chaining you can use IEnumerable<T>.Concat() (and than .ToList() in your case). This approach will give you new list and would be useful if result of GetBunch is :
GetBunch(index)
.Concat(Enumerable.Repeat(new Thingy() { ... }, 1))
.ToList()
NOTE: If your GetBunch would return generic IList<T> or IEnumerable<T> than you can use helper methods of Enumerable (like .Concat()). Since it returns non-generic version you need to convert it to generic variant with something like Enumerable.Cast or cast to generic interface to use LINQ approach. You need to know what actual type is there OR what type of items should be returned.
GetBunch(index).Cast<object>()
GetBunch(index) as IList<Thingy>
return table.Rows.Cast<DataRow>()
.Select(row => new Something
{
Field = row["field1"] as int?,
Bunch = GetBunch(index).Union(x =>
new[] { new Thingy() { ... } }
).ToList()
});

If method returns interface type, why can't I pass the result to a concrete type?

The question maybe a little confusing, but it's hard to make clear this question in a subject title.
I have method declared and implemented like this:
public IList<string> GetBookTitles()
{
IList<string> bookTitles = new List<string>();
// do something to populate the bookTitles list.
return bookTitles;
}
Why can't I pass the result of this method to a List<string>? After all, List<string> is a kind of IList<string>.
Well, for starters, just look at the members of IList and compare it with List. List has methods that an IList doesn't. (List has a BinarySearch method that IList doesn't, just as a single example.)
Arrays also implement IList, as an example. An array however is not a List, so you can't, and shouldn't, be able to pass a string[] to a method that accepts a List<string>.
You have a few possible solutions. One would be to just change your method to return a List<string> rather than an IList<string> (that's what I'd suggest). If that's what you really need then you shouldn't be restricting the return type to IList<string>. Another (poorer) option would be to cast the result back to a List<string> before passing it to the next method, since you happen to know that it's what the underlying type really is.
After all, List<string> is a kind of IList<string>.
But there are also other kinds of IList<String>.
What if your method were to return an IList<String> which is a ReadOnlyCollection<String> instead?
IList<string> x = new ReadOnlyCollection<string>();
List<string> y = x; //Huh?
The compiler uses the signature of your methods, not the implementation when deciding if you can assign the result of GetBookTitles to your variable, so it can't know that the result will in fact be a List. If it would allow you to do such a thing, then you could write something like this:
List<string> myBooks = GetBookTitles();
myBooks.Sort();
In your example you could do this, and in fact you can if you cast the result of your method:
List<string> myBooks = (List<string>)GetBookTitles();
But then one day you could decide that your book collection is not modifiable, and you rewrite your method as follows:
public IList<string> GetBookTitles()
{
IList<string> tmp = new List<string>();
// do something to populate the bookTitles list.
IList<string> bookTitles = new ReadOnlyCollection<string>(tmp);
return bookTitles;
}
ReadOnlyCollection does not implement Sort, so your app would compile, but would crash at runtime.
Using the cast approach it would crash when trying to do the cast, but in this case you are taking the responsibility of deciding that that kind of cast is feasible and do not have the compiler trying to guess.
A better approach could be to use as instead of the cast and chek for null. I.e.:
List<string> myBooks = GetBookTitles() as List<string>;
if (myBooks != null)
myBooks.Sort();
You should be able to, you just need an explicit conversion.
List<string> foo = (List<string>)GetBookTitles()
should do it.
The interface may be implemented in various classes which are not same. So, it will be difficult to find the respective class.
You can type cast from IList to List!!!

Could not find an implementation of the query pattern Error

Given
var selectedItems = listBoxControl1.SelectedItems;
var selectedItemsList = (from i in selectedItems
select i).ToList();
I receive Error
Could not find an implementation of the query pattern for source type
'DevExpress.XtraEditors.BaseListBoxControl.SelectedItemCollection'.
'Select' not found. Consider explicitly specifying the type of the
range variable 'i'.
using system.LINQ Done
I can use foreach so it must implement IEnumerable. I prefer to use LINQ over foreach to gather each string, if possible.
I want to take the ToString() values for each SelectedItem in the list box control and stick them in a List<string>. How can I do it?
I can use foreach so it must implement IEnumerable.
That's not actually true, but it's irrelevant here. It does implement IEnumerable, but not IEnumerable<T> which is what LINQ works over.
What's actually in the list? If it's already strings, you could use:
var selectedItemsList = selectedItems.Cast<string>().ToList();
Or if it's "any objects" and you want to call ToString you can use:
var selectedItemsList = selectedItems.Cast<object>()
.Select(x => x.ToString())
.ToList();
Note that the call to Cast is why the error message suggested using an explicitly typed range variable - a query expression starting with from Foo foo in bar will be converted to bar.Cast<Foo>()...
For LINQ to work, you need an IEnumerable<T>, straight IEnumerable isn't enough. Try:
var selectedItems = listboxControl1.SelectedItems.Cast<T> //where T is the actual type of the item
Try just
var result = listBoxControl1.SelectedItems.Cast<MyItemType>().ToList();

How to get an empty list of a collection?

I have a collection of anonymous class and I want to return an empty list of it.
What is the best readable expression to use?
I though of the following but I don't think they are readably enough:
var result = MyCollection.Take(0).ToList();
var result = MyCollection.Where(p => false).ToList();
Note: I don't want to empty the collection itself.
Any suggestion!
Whats about:
Enumerable.Empty<T>();
This returns an empty enumerable which is of type T. If you really want a List so you are free to do this:
Enumerable.Empty<T>().ToList<T>();
Actually, if you use a generic extension you don't even have to use any Linq to achieve this, you already have the anonymous type exposed through T
public static IList<T> GetEmptyList<T>(this IEnumerable<T> source)
{
return new List<T>();
}
var emp = MyCollection.GetEmptyList();
Given that your first suggestion works and should perform well - if readability is the only issue, why not create an extension method:
public static IList<T> CreateEmptyCopy(this IEnumerable<T> source)
{
return source.Take(0).ToList();
}
Now you can refactor your example to
var result = MyCollection.CreateEmptyCopy();
For performance reasons, you should stick with the first option you came up with.
The other one would iterate over the entire collection before returning an empty list.
Because the anonymous type there is no way, in source code, to create a list. There is, however, a way to create such list through reflection.

C# convert reflection.propertyinfo to Generic.List<>

How do I go about converting a reflection.propertyinfo[] to a generic.list<>?
One of the List<T> constructors accepts an IEnumerable<T> as its argument (i.e., your PropertyInfo array):
var list = new List<PropertyInfo>( propInfoArray );
var list = yourArray.ToList();
Try using .ToList()
http://msdn.microsoft.com/en-us/library/bb342261.aspx
All of the above are correct. But it should also be mentioned that, like List<T> all .net arrays implement IList<T>.
var IList<PropertyInfo> ilist = reflection.propertyinfo;
Since I know that, almost all my functions accept IList<T> when I need a list-like collection, which I can use with traditional arrays and lists.
Use the extension method ToList() available in the System.Linq namespace:
var myProperties = propertyInfoArray.ToList();

Categories

Resources