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

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);

Related

Convert IEnumerable to type that implements IEnumerable

GIVEN:
If you have the values:
Type type
IEnumerable enumerable
And the following conditions are met:
typeof(IEnumerable).IsAssignableFrom(type)
enumerable.All(element => element.GetType() == type.GetElementType())
GENERAL QUESTION:
Is it possible to create an instance of type via reflection that contains all of the elements of enumerable?
BACKGROUND:
Most of the types in System.Collections have a constructor like Example(ICollection), and if type has a constructor like that it is simple and straightforward to do Activator.CreateInstance(type, enumerable). For types like Dictionary<TKey, TValue> though, it is not that simple. The only solution I have thought of looks like this:
var dictionary = (IDictionary) Activator.CreateInstance(type);
var elementType = enumerable.First().GetType();
var key = elementType.GetProperty("Key");
var value = elementType.GetProperty("Value");
foreach (var element in enumerable)
{
dictionary.Add(key.GetValue(element), value.GetValue(element));
}
I would be more willing to accept this solution of KeyValuePair<TKey, TValue>implemented an interface which contained the properties Key and Value so you could say:
var keyValuePair = (IKeyValuePair) element;
dictionary.Add(keyValuePair.Key, keyValuePair.Value);
rather than relying on reflection to get the aforementioned property values.
This solution would only work for types within System.Collections or custom types that strongly adhere to the definitions of said types.
SPECIFIC QUESTION:
Is there a more elegant way of converting enumerable to the type of typethat also could account for edge cases like MyCollection : ICollection, where the type definition is not known to us?
UPDATE:
Here is an example:
var original = new Dictionary<int, string>
{
//values
};
var type = original.GetType();
var enumerable = original.AsEnumerable();
var copy = (Dictionary<int, string>) DoSomeMagic(type, enumerable);
object DoSomeMagic(Type type, IEnumerable enumerable)
{
//Add magic here
}
This is one of the few reasons left to use good old ArrayList.
System.Array ConvertUnknownIEnumerableToArray(IEnumerable ienumerable, Type type)
{
var list = new ArrayList();
foreach (var i in ienumerable) list.Add(i);
return list.ToArray(type);
}
The above creates a strongly typed array (named array) of the concrete objects contained in any enumerable named ienumerable. An array, of course, implements ICollection.
This technique allows you to avoid Reflection figuring out which generic MethodInfo to create and invoke to create the array. The framework does it for you.

convert an List<Keyvaluepair> to a specific ICollection type C#

`Please am new-bee to programming and also have searched for the last few hours on a solution but cant find one; So here is my problem:
I have a List<KeyValuePair<string, object>> I want to convert the value pair at run-time to a ICollection<T>
Where T is the Type of object (The Value pair).
The purpose of the conversion is to pass the values into the PropertyInfo.SetValue(obj, val) method. Where val is the ICollection
public object TheMEthod( object objreactor, List<KeyValuePair<string, object>> objactor) {
Type tyr2 = typeof(List<>).MakeGenericType(objactor.First().Value.GetType());
ICollection list = (ICollection) Activator.CreateInstance(tyr2);
list = (ICollection) objactor.Select(l => l.Value).Distinct().ToList();
objreactor.GetType().GetProperty(objactor.First().Key)?.SetValue(objreactor, Convert.ChangeType( list, objactor.First().Value.GetType()), null);
//else return exception
return objreactor;
}
This returns the error object must implement iconvertible c#"
If the keyvalue pair has an object as the value, but you need it to be a specific object T you'll need to cast it. This will only work if the Value really is the right type.
List<KeyValuePair<string, object>> list = ....
ICollection<TheRealObject> coll = list.Select(x => x.Value) // Select the Values
.Cast<TheRealObject>() //Cast them to your type
.ToList(); // turn it to a list
Note that List<T> is a ICollection<T> so you can almost certainly pass this list to a SetProperty expecting an ICollection<T>

Convert boxed ienumerable into object array without knowing explicit type

I've got a little code that pulls a boxed ienumerable instance out of an expression tree. The code needs to convert it into object[].
So far I've gotten away with assuming it'll be IEnumerable<string> and thus casting it followed with .ToArray().
Circumstances have changed and now it could also possibly be a IEnumerable<int>. I still need to change the box into an object[] and don't really care what the type is.
object list = Expression.Lambda(methodCallExpression.Object).Compile().DynamicInvoke();
var enumerable = (IEnumerable<string>)list;
object[] values = enumerable.ToArray();
UPDATE:
Strings are references and Integers are value types. I've found that while I can box the reference to an array of ints, I cannot pretend it's an array of boxed ints as int's cannot be boxed.
An exception of type 'System.InvalidCastException' occurred in
System.Core.dll but was not handled in user code Additional
information: Unable to cast object of type
'System.Collections.Generic.List1[System.Int32]' to type
'System.Collections.Generic.IEnumerable1[System.Object]'.
object list = Expression.Lambda(methodCallExpression.Object).Compile().DynamicInvoke();
var enumerable = (IEnumerable<object>)list;
object[] values = enumerable.ToArray();
Just call Cast before ToArray:
object[] values = enumerable.Cast<object>().ToArray();
Note that this casts each item, not the entire collection. You can't "cast" a collection of ints to a collection of objects, you have to convert each item to an object (i.e. box them).
Previously answered in Best way to convert IList or IEnumerable to Array.
Or you could do it the hard way:
IEnumerable enumberable = (IEnumerable)list;
List<object> values = new List<object>();
foreach (object obj in enumerable)
{
values.Add(obj);
}
Haven't tested it, but you could theoretically cast it to IEnumerable<object> using Linq:
object [] values = ((IEnumerable)list).Cast<object>().ToArray();

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");
}

Convert IEnumerable in List<T>

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.

Categories

Resources