How to convert IEnumerable to ObservableCollection?
As per the MSDN
var myObservableCollection = new ObservableCollection<YourType>(myIEnumerable);
This will make a shallow copy of the current IEnumerable and turn it in to a ObservableCollection.
If you're working with non-generic IEnumerable you can do it this way:
public ObservableCollection<object> Convert(IEnumerable original)
{
return new ObservableCollection<object>(original.Cast<object>());
}
If you're working with generic IEnumerable<T> you can do it this way:
public ObservableCollection<T> Convert<T>(IEnumerable<T> original)
{
return new ObservableCollection<T>(original);
}
If you're working with non-generic IEnumerable but know the type of elements, you can do it this way:
public ObservableCollection<T> Convert<T>(IEnumerable original)
{
return new ObservableCollection<T>(original.Cast<T>());
}
To make things even more simple you can create an Extension method out of it.
public static class Extensions
{
public static ObservableCollection<T> ToObservableCollection<T>(this IEnumerable<T> col)
{
return new ObservableCollection<T>(col);
}
}
Then you can call the method on every IEnumerable
var lst = new List<object>().ToObservableCollection();
ObservableCollection<decimal> distinctPkgIdList = new ObservableCollection<decimal>();
guPackgIds.Distinct().ToList().ForEach(i => distinctPkgIdList.Add(i));
// distinctPkgIdList - ObservableCollection
// guPackgIds.Distinct() - IEnumerable
The C# Function to Convert the IEnumerable to ObservableCollection
private ObservableCollection<dynamic> IEnumeratorToObservableCollection(IEnumerable source)
{
ObservableCollection<dynamic> SourceCollection = new ObservableCollection<dynamic>();
IEnumerator enumItem = source.GetEnumerator();
var gType = source.GetType();
string collectionFullName = gType.FullName;
Type[] genericTypes = gType.GetGenericArguments();
string className = genericTypes[0].Name;
string classFullName = genericTypes[0].FullName;
string assName = (classFullName.Split('.'))[0];
// Get the type contained in the name string
Type type = Type.GetType(classFullName, true);
// create an instance of that type
object instance = Activator.CreateInstance(type);
List<PropertyInfo> oProperty = instance.GetType().GetProperties().ToList();
while (enumItem.MoveNext())
{
Object instanceInner = Activator.CreateInstance(type);
var x = enumItem.Current;
foreach (var item in oProperty)
{
if (x.GetType().GetProperty(item.Name) != null)
{
var propertyValue = x.GetType().GetProperty(item.Name).GetValue(x, null);
if (propertyValue != null)
{
PropertyInfo prop = type.GetProperty(item.Name);
prop.SetValue(instanceInner, propertyValue, null);
}
}
}
SourceCollection.Add(instanceInner);
}
return SourceCollection;
}
Related
I'm trying to create a generic Entity Framework class that I can use to get typed lists. I'm modeling it after this: How can I use Activator.CreateInstance to create a List<T> where T is unknown at runtime?
The problem I'm having is that my type - targetType.GetInterfaces() - doesn't return any interfaces. When I try to add items, I get a constructor error.
list.Add(Activator.CreateInstance(targetType,obj))); Throws Constructor on Type myType Not Found
Here is the usage:
List<myType> myVariable = new List<myType>();
myVariable = ListTableContents((dynamic)(new myType()).GetType());
public static IList ListTableContents(Type targetType )
{
using (var db = new myContext())
{
var method = typeof(DbContext).GetMethod("Set").MakeGenericMethod(targetType);
var query = method.Invoke(db, null) as IQueryable;
// This works - I have a list of objects
List<object> retObj = query.OfType<object>().ToList();
Type iListType = typeof(IList);
if (!targetType.GetInterfaces().Contains(iListType))
{
// hits this every time
throw new ArgumentException("No IList", nameof(targetType));
}
Type elementType = targetType.GenericTypeArguments.FirstOrDefault();
IList list = Activator.CreateInstance(targetType) as IList;
foreach (var obj in retObj)
{
// Constructor Not Found
list.Add(Activator.CreateInstance(targetType, obj));
}
return list;
}
}
Here is the class constructor. As you can see, it's Entity Framework:
public partial class myType
{
public myType()
{
myTypes = new HashSet<myType>();
}
public string myTypeStringType { get; set; }
public int myTypeID { get; set; }
public virtual ICollection<myType> myTypes { get; set; }
}
Any help would be greatly appreciated.
The problem was that I didn't have a class constructor that took an object. I solved it by adding a dynamic cast method.
Usage:
List myList = ListTableContents((dynamic)(new myType()).GetType());
Methods:
// This returns the entire table as a list of classes
public static IList ListTableContents(Type targetType)
{
using (var db = new myContext())
{
var method = typeof(DbContext).GetMethod("Set").MakeGenericMethod(targetType);
var query = method.Invoke(db, null) as IQueryable;
List<object> retObj = query.OfType<object>().ToList();
// Create a list of the required type and cast to IList
Type genericListType = typeof(List<>);
Type concreteListType = genericListType.MakeGenericType(targetType);
IList list = Activator.CreateInstance(concreteListType) as IList;
// Add values
foreach (var obj in retObj)
{
list.Add(Cast(obj, targetType));
}
return list;
}
}
public static dynamic Cast(dynamic obj, Type castTo)
{
return Convert.ChangeType(obj, castTo);
}
I don't know who resolve this segment code with variance:
I have an abstract father class:
public abstract class PdfObject
{...}
And two child classes:
public class PdfText : PdfObject
{...}
public class PdfImage : PdfObject
{...}
Now, my wrong or empiric code is the next:
public IList<PdfText> GetTexts()
{
List<PdfText> result = new List<PdfText>();
List<PdfObject> list = GetList();
foreach(var item in list)
{
if(item is PdfText) result.Add(item)
}
return result;
}
public List<PdfObject> GetList()
{...}
Well, i read a lot of this theme, but don't stand how use variance in generics or use a better solution for this issue.
Please, help me and thanks.
This doesn't have much to do with variance, directly. Your problem is here:
public IList<PdfText> GetTexts()
{
List<PdfText> result = new List<PdfText>();
List<PdfObject> list = GetList();
foreach(var item in list)
{
if(item is PdfText) result.Add(item)
}
return result;
}
The static type of the item variable is PdfObject so you cannot add it to result; you need to cast it. For example
if (item is PdfText) result.Add((PdfText)item);
This is inefficient because you check the type twice: once for the is operator and once for the cast. Instead, you're supposed to do this:
public IList<PdfText> GetTexts()
{
List<PdfText> result = new List<PdfText>();
List<PdfObject> list = GetList();
foreach(var item in list)
{
var textItem = item as PdfText
if (textItem != null) result.Add(textItem)
}
return result;
}
Or, you can use linq:
var result = GetList().OfType<PdfText>().ToList();
You could do this...
public IList<PdfText> GetTexts()
{
List<PdfText> result = GetList()
.Where(x => x is PdfText)
.Select(x => (PdfText)x)
.ToList();
return result;
}
Edited: This works, but OfType is better.
You could have a better solution in this situation.
public class ClientOfPdfObject<T> where T: PdfObject
{
public List<T> GetItems()
{
List<PdfObject> list = GetList();
var result = new List<T>();
foreach (var pdfObject in list)
{
if (typeof (T) == pdfObject.GetType())
result.Add((T) pdfObject);
}
return result;
}
//Get PdfObjects somewhere (ex. Db)
private List<PdfObject> GetList()
{
var list = new List<PdfObject>
{
new PdfImage(),
new PdfImage(),
new PdfImage(),
new PdfText(),
new PdfText(),
new PdfText(),
new PdfText()
};
return list;
}
}
static void main()
{
var text = new ClientOfPdfObject<PdfText>();
//contains 4 itmes (PdfText)
var pdfTexts = text.GetItems();
var image = new ClientOfPdfObject<PdfImage>();
//contains 3 items (PdfImage)
var pdfImages = image.GetItems();
}
Tomorrow, when you add more pdf objects (ex. PdfGraph), you don't need to change anything.
I am implementing some kind of deserialization and struggled with a next problem:
I have List<object> and System.Reflection.Field, it's FieldType can be List<string>, List<int> or List<bool>, so I need to convert from List<object> to that types.
public static object ConvertList(List<object> value, Type type)
{
//type may be List<int>, List<bool>, List<string>
}
I can write each case separately, but there should be a better way using reflection.
I believe what you want is:
public static object ConvertList(List<object> value, Type type)
{
var containedType = type.GenericTypeArguments.First();
return value.Select(item => Convert.ChangeType(item, containedType)).ToList();
}
Example usage:
var objects = new List<Object> { 1, 2, 3, 4 };
ConvertList(objects, typeof(List<int>)).Dump();
I'm not sure how useful this is though... It highlights the insanely useful Convert.ChangeType method I guess!
Update: Since others have correctly pointed out that this doesn't actually return a List<T> (where T is the type in question) and therefore might not fully answer the question at hand, I have chosen to provide a more up to date answer:
public static object ConvertList(List<object> items, Type type, bool performConversion = false)
{
var containedType = type.GenericTypeArguments.First();
var enumerableType = typeof(System.Linq.Enumerable);
var castMethod = enumerableType.GetMethod(nameof(System.Linq.Enumerable.Cast)).MakeGenericMethod(containedType);
var toListMethod = enumerableType.GetMethod(nameof(System.Linq.Enumerable.ToList)).MakeGenericMethod(containedType);
IEnumerable<object> itemsToCast;
if(performConversion)
{
itemsToCast = items.Select(item => Convert.ChangeType(item, containedType));
}
else
{
itemsToCast = items;
}
var castedItems = castMethod.Invoke(null, new[] { itemsToCast });
return toListMethod.Invoke(null, new[] { castedItems });
}
If you don't need the conversion (so the type of each value is actually correct, and you don't have ints in strings etc), then remove the performConversion flag and the associated block.
Example: https://dotnetfiddle.net/nSFq22
Not sure if this helps at all, but can you use Linq Cast?
List<object> theList = new List<object>(){ 1, 2, 3};
List<int> listAsInt = theList.Cast<int>().ToList();
The type is only known at runtime so I guess generic method isn't the way to go
public static object ConvertList(List<object> value, Type type)
{
IList list = (IList)Activator.CreateInstance(type);
foreach (var item in value)
{
list.Add(item);
}
return list;
}
/// <summary>
/// Converts list of items into typed list of item of new type
/// </summary>
/// <example><code>
/// Consider source to be List<object>, newItemType is typeof(string), so resulting list wil have type List<string>
/// </code></example>
/// <param name="newItemType">New item type</param>
/// <param name="source">List of objects</param>
/// <returns>Typed List object</returns>
public static IList ConvertList(Type newItemType, IList source)
{
var listType = typeof(List<>);
Type[] typeArgs = { newItemType };
var genericListType = listType.MakeGenericType(typeArgs);
var typedList = (IList)Activator.CreateInstance(genericListType);
foreach (var item in source)
{
typedList.Add(item);
}
return typedList;
}
public static object ConvertList<T>(List<object> value) where T : class
{
var newlist = value.Cast<T>().ToList();
return newlist;
}
or
public static List<T> ConvertList<T>(List<object> value) where T : class
{
List<T> newlist = value.Cast<T>().ToList();
return newlist;
}
Try this:
public static List<T> ConvertList<T>(List<object> list)
{
List<T> castedList = list.Select(x => (T)x);
return castedList;
}
Call:
List<object> myList = new List<object> {"test", "foo", "bar"};
List<string> stringList = ConvertList<string>(myList);
public static List<T> ConvertType<T>(List<object> list) {
var list2 = new List<T>();
for(int i=0;i<list.Count;i++) list2.Add((T)list[i]);
return list2;
}
Here is an extension method similar to the linq extension method except it takes an argument that is a type instead of a type parameter:
public static IList CastToList(this IEnumerable source, Type itemType)
{
var listType = typeof(List<>).MakeGenericType(itemType);
var list = (IList)Activator.CreateInstance(listType);
foreach (var item in source) list.Add(item);
return list;
}
Usage:
var list = new List<object>();
list.add(1);
list.add(2);
var boxedIntList = list.CastToList(typeof(int)); //type is object{List<int>}
I have a list of objects created using reflection, they are all the same type, however the type is unknown at compile time.
I'm trying to figure out the best way of assigning this list (also using reflection) to an object property which could be any IEnumerable.
List<object>
ArrayList
Custom : List<object>
The only approach I have is to assume the property is an ICollection then loop through the IEnumerable and add each item. (See below, where list is the IEnumerable source, key is the string name of the object property and result is the object itself)
foreach (object item in list) {
PropertyInfo prop = result.GetType().GetProperty(key);
var collection = prop.GetValue(result, null);
Type collectionType = collection.GetType();
MethodInfo add = collectionType.GetMethod("Add", BindingFlags.Public | BindingFlags.Instance);
add.Invoke(collection, new object[] { item });
}
Since you say the data is homogeous, I would suggest typing it as closely as you can; so assuming list is non-empty, list[0].GetType() will tell you the Type of all the data. At this point, you could do:
IList typedList = (IList)Activator.CreateInstance(
typeof(List<>).MakeGenericType(itemType));
...
foreach(var item in list) typedListAdd(item);
or you could use an array:
Array arr = Array.CreateInstance(itemCount, list.Count);
list.CopyTo(arr, 0);
Either of which will give you a well typed list, which tends to work much better for most purposes (data-binding, serialization, or just reflection).
If list is not actually a list, but is just IEnumerable, then you can basically still do the same thing, but simply defer the creation until the first item:
IList typedList = null;
foreach(object item in list) {
if(typedList == null) {
typedList = (IList)Activator.CreateInstance(
typeof(List<>).MakeGenericType(item.GetType()));
}
typedList.Add(item);
}
return typedList ?? new object[0];
There are a couple of ways that you can add items to an existing collection of not known type:
Check for the IList interface or check of an Add method as a fallback;
public void Add(object obj, string propertyName, IEnumerable enumerable)
{
Action<object> add;
PropertyInfo prop = obj.GetType().GetProperty(propertyName);
var property = prop.GetValue(obj, null);
var collection = property as IList;
// Check for IList
if(collection != null)
{
add = item => collection.Add(item);
}
// Try to get an Add method as fallback
else
{
var objType = obj.GetType();
var addMethod = objType.GetMethod("Add", BindingFlags.Public | BindingFlags.Instance);
// Property doesn't support Adding
if(addMethod == null) throw new InvalidOperationException("Method Add does not exist on class " + objType.Name);
add = item => addMethod.Invoke(obj, new object[] { item });
}
foreach (var item in enumerable)
{
add(item);
}
}
I would probably go with Marc's way since it's more type safe.
public class Foo
{
public Foo()
{
Bar = new List<string>();
}
public List<string> Bar { get; set; }
public string Qux { get; set; }
}
var result = new Foo();
var key = "Bar";
var list = new List<object> { "A", "B" };
Add(result, key, list);
I am trying to create a list of a certain type.
I want to use the List notation but all I know is a "System.Type"
The type a have is variable. How can I create a list of a variable type?
I want something similar to this code.
public IList createListOfMyType(Type myType)
{
return new List<myType>();
}
Something like this should work.
public IList createList(Type myType)
{
Type genericListType = typeof(List<>).MakeGenericType(myType);
return (IList)Activator.CreateInstance(genericListType);
}
You could use Reflections, here is a sample:
Type mytype = typeof (int);
Type listGenericType = typeof (List<>);
Type list = listGenericType.MakeGenericType(mytype);
ConstructorInfo ci = list.GetConstructor(new Type[] {});
List<int> listInt = (List<int>)ci.Invoke(new object[] {});
Thank you! This was a great help. Here's my implementation for Entity Framework:
public System.Collections.IList TableData(string tableName, ref IList<string> errors)
{
System.Collections.IList results = null;
using (CRMEntities db = new CRMEntities())
{
Type T = db.GetType().GetProperties().Where(w => w.PropertyType.IsGenericType && w.PropertyType.GetGenericTypeDefinition() == typeof(System.Data.Entity.DbSet<>)).Select(s => s.PropertyType.GetGenericArguments()[0]).FirstOrDefault(f => f.Name == tableName);
try
{
results = Utils.CreateList(T);
if (T != null)
{
IQueryable qrySet = db.Set(T).AsQueryable();
foreach (var entry in qrySet)
{
results.Add(entry);
}
}
}
catch (Exception ex)
{
errors = Utils.ReadException(ex);
}
}
return results;
}
public static System.Collections.IList CreateList(Type myType)
{
Type genericListType = typeof(List<>).MakeGenericType(myType);
return (System.Collections.IList)Activator.CreateInstance(genericListType);
}