Convert IEnumerable in List<T> - c#

I am creating a control that receive in datasource a DataSet or List
How i convert a IEnumerable to List in a CreateChildControls event?
protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
{
if (dataSource is System.Data.DataSet)
{
}
else if(dataSource is IList)
{
}
}

Usually one would use the IEnumerable<T>.ToList() extensionmethod from Linq but in your case you can not use it (right away) because you have the non-generic IEnumerable interface. Sou you will have to cast it first (also using Linq):
datasource.Cast<object>().ToList();
No matter what you original collection actually ist, this will always succeed.

I re-read your question and it seems that you are receiving a dataset which is ALREADY a list OR a DataSet, but it is cast to an IEnumerable. In this case, simply do
IList myList = (IList)datasource //will throw exception if invalid
or
IList myList = datasource as IList //mylist will be null if conversion cannot be made

To answer your question 'how i can get the original Type and not set a object type?'.
Every type in .NET framework contains GetType method to fetch the type of the specified object. You can use it before ToList method.

Related

Convert object (which is a List<T>) to List<object>

The method I am overriding has the following signature.
public override bool IsValid(object value)
The object that is passed in is a List but the the list type is unknown. It could be List<string> or List<int>.
I need to cast this into a List<object>. I've tried
if (!(value is IList temp))
{
return false;
}
List<object> list = temp.OfType<object>().ToList();
which sort of works, but it filters out any null values, presumably because they are not OfType<object>
So what's the best way of doing this?
temp.OfType().ToList();
OfType checks if the element is of the required type, and if so it puts it in a new temporary list.
What you're asking is simply a cast, since every instance in C# is an object: (List<object>)temp. Edit: apparently covariance doesn't work here.
There's absolutely no reason to do this though, you can simply enumerate it as it is: foreach(var obj in (IList)temp). All collections implement the IList non-generic interface.
If the input is either List<int> or List<string> and nothing else, then I think the best approach is to check specifically for these types. So something like:
List<object> list ;
if (value is List<int> listOfInts)
{
list = listOfInts.Cast<object>().ToList();
}
else if (value is List<string> listOfStrings)
{
list = listOfStrings.Cast<object>().ToList();
}
else
{
throw new ArgumentException(...);
}
This might seem redundant, but it might save you a lot of headache down the line, since you will catch if someone passes a List<SomethingElse> or even a List<object> which would be illegal according to your specification.

How to retrieve data from an ICollection<T> where T is unknown

I know that my type is a ICollection<T>. I know that T is a primitive type, and I know that T can be turned into a string with ToString(). I have the Type object of T (By using: Type genericType = info.PropertyType.GenericTypeArguments[0];
I do not know how to get the items in that collection out and into another collection of a known type (Like a List<string>). Thankfully because all I want are the values of it's items as a string I can use ToString() on each one regardless of it's type (constrained to primitives).
I use this in another area of my program to get the values of all the properties of a class as long as they are primitive. I have tried casting the Type object as the generic argument for an ICollection<T> and that did not work.
Edit: I have an object that I know is an ICollection<T>, but I cannot seem use LINQ on it till it's casted to an ICollection<T>, I cannot cast to that because T is "unknown" (I have retrieved the Type of T but am not sure where to run with that).
Since you start with generic collection and ICollection<T> implements IEnumerable<T>, you can use LINQ:
List<string> res = coll.Select(elem => elem.ToString()).ToList();
Edit - you can cast the object to non-generic IEnumerable or ICollection, then call Cast<object> on that to get a generic collection (you can do that because you just want to call ToString on elements):
object obj = new List<int> { 1, 2, 3 };
IEnumerable res = obj as IEnumerable;
List<string> result = res.Cast<object>().Select(e => e.ToString()).ToList();
foreach (var e in result)
Console.WriteLine(e);

Convert SelectedObjectCollection to Collection of Specific Type

I have a WinForms multiselect listbox, and each item in the listbox is of type MyClass.
I am also writing a method that needs to take a parameter that is a collection of MyClass. It could be of type MyClass[], List<MyClass>, IList<MyClass>, IEnumerable<MyClass>, etc. Any of those would work fine.
Somehow, I need to pass the selected items in the listbox to my method. But how would I convert SelectedObjectCollection to any of the MyClass collection types described above?
Maybe this helps:
IEnumerable<MyClass> items = yourListBox.SelectedItems.Cast<MyClass>();
One issue is that ListBox Items are not a generic list, so it could contain more than one type. If you call on .AsQueryable you are making the explicit cast on a non type-safe collection when you call on .Select(), Same goes with calling .Cast<T>, as you could get a cast exception. A safer approach would be to use .OfType<T>()
IEnumerable<MyClass> selected = listBox.SelectedItems.OfType<MyClass>();
You can try Linq:
yourSelectedObjectCollection.AsQueryable().Select(o=>(MyClass)o).ToArray()
I had the same issue with my TreeView, which contained 2 different classes.
if(SelectedItem is MyClass)
{
MyClass passvariable = (MyClass)SelectedItem;
}
So if you select an item and the type of the item is MyClass, you create a new variable and set it with the SelectedItem as type MyClass.
You can do the same with a Collection, List, ...
if(MyList is ObservableCollection<MyClass>)
{
ObservableCollection<MyClass> passlist = (ObservableCollection<MyClass>)MyList;
}
If you have more then 1 class in a ListBox, ComboBox, ... just check the SelectedItem with if(... is type)

How to check if an object is a list enum type objects?

I have an object that can be a list of different enum types or non-enum types (normal class instances).
To verify if object is a list is easy:
myobject is IList
Now I can verify the type of list's elements:
(myobject as IList)[0].GetType().IsEnum
But how to verify if my list's elements are enums IF I have no elements yet ?
if (myobject is IList)
{
if ((myobject as IList).Count > 0)
{
if ((myobject as IList)[0].GetType().IsEnum)
return true;
}
else
{
// how to check if the list is enum list here ?
}
}
An IList can contain whatever type it wants, so if you don't have any contents you have no way of checking. If you actually have a generic type to start with you can check by using the GetGenericArguments method of Type. (GetInterface added in case you have something that's implementing IList but doesn't have the IList type as it's first generic argument).
myobject.GetType().GetInterface("System.Collections.Generic.IList").GetGenericArguments()[0].IsEnum
You can look at the the indexer's PropertyType via Type.GetProperty:
List<int> list = new List<int>(); // an empty List<T>
Type type = list.GetType().GetProperty("Item").PropertyType; // System.Int32
bool isEnum = type.IsEnum; // of course false
List<DayOfWeek> days = new List<DayOfWeek>();
type = days.GetType().GetProperty("Item").PropertyType;
isEnum = type.IsEnum; // true
demo: http://ideone.com/3JyEf
Having just IList you can't do that - IList does not gurantee types of objects inside of it and does not let you know type of objects it would accept.
Consider uisng generic veriosn IList<T> if possible - you'll be able to get type without elements in the list.
Unless your list is a generic list you cannot, since a non generic list may contain any object.
If list is generic then inspect generic type parameters for enum types.
If list is not generic try to resolve item type by inspecting parameters of Add, IndexOf or indexer methods. It is a very ugly way to do it, but may give you a clue since many old implementations inherits List object and adds an Add overload, or some new and lazy implementations may be used to hide generic parameters like public class MyObjectList: List<MyObject> {}.
The solution everyone is proposing:
IList<Days> list = new List<Days>();
if (list is IList<Days>)
{
Console.WriteLine("list has days");
}

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.

Categories

Resources