[CrossPost From MSDN]
I had a task that, I need to send a generic List to a method, where I need to iterate it and convert it to an Excel File. I already did this with Data Table, but with Generic list I am facing some problems (I don't want to convert my generic list to Data Table). I will paste the code which helps me out for an answer.
I Had Two Generic Lists
List<User> objList = new List<User>();
List<Student> objStudent = new List<Student>();
// I am adding some Item to List
User obj = new User(1, "aaa");
User obj1 = new User(2, "bbb");
User obj2 = new User(3, "ccc");
User obj3 = new User(4, "ddd");
Student sobj = new Student(1, "aaa");
Student sobj1 = new Student(2, "bbb");
Student sobj2 = new Student(3, "ccc");
Student sobj3 = new Student(4, "ddd");
objList.Add(obj);ExportToExcel(objList);
To Export it to Excel , I am passing the lists to the below methods as
public void ExportToExcel<T>(IEnumerable<T> list)
{
PropertyInfo[] piT = typeof(T).GetProperties();
var Users = list.ToList();
Type myType = (typeof(T));
}
When I am passing my list to Ienumerable... I am not able to retrieve the data present in the List IEnumerable list. If I retrieve the data , then I can handle further. Could any one suggest me the better Idea?
If your always going to work with List<T> you could change IEnumerable<T> to IList<T>. AFAIK the IEnumerable interface does not define methods for accessing the data inside the collection, only to iterate it.
You could even use ICollection<T> if it suits your needs.
If you need to access the values of all the properties on type T, you can use the PropertyInfo.GetValue method:
public void ExportToExcel<T>(IEnumerable<T> items)
{
var properties = typeof(T).GetProperties();
foreach(var item in items)
{
foreach(var property in properties)
{
var value = property.GetValue(item, null);
// Do something else with the property's value
}
}
}
Edit in response to comment
You indicated you might receive a single list or a list of lists. You can add another overload which takes the composed lists, then iterate through it and export each individual list:
public void ExportToExcel<T>(IEnumerable<IEnumerable<T>> itemSets)
{
foreach(var itemSet in itemSets)
{
ExportToExcel(itemSet);
}
}
Related
This question already has answers here:
Item from IEnumerable changed inside foreach, but change not saved to collection
(1 answer)
C# failing to set property inside IEnumerable
(5 answers)
Closed 3 years ago.
I have this code:
class Foo
{
public string A { get; set; }
}
class Program
{
static void Main(string[] args)
{
var strings = new List<string> { "foo", "foo" };
var list = strings.Select(x => new Foo { A = x });
foreach (var item in list)
{
item.A = "bar";
}
foreach (var item in list)
{
Console.WriteLine(item.A);
}
}
}
Which prints:
foo
foo
What exactly happens when you set item.A = "bar" ?
After the first foreach loop finishes, does the list var really contain the same two Foo objects with "bar" as the new string?
If so, how could you access these new values?
I understand that when the 2nd foreach loop runs, it is enumerating the collection of strings which is why you get two print outs of "foo", but I'm just confused as to what happens when item.A = "bar" is run, and if you are never able to access that new value, why does the compiler allow you to modify it?
What's happening here is that you are creating an enumerable list which you are enumerating multiple times.
Each time you enumerate list, the enumeration processes the elements of the strings list calling new Foo { A = x } for each element to create the elements of the resulting sequence.
That means the the Foo objects created by the first foreach enumeration are NOT the same as the ones created by the second foreach enumeration. New ones are created for each enumeration.
This is the reason that Resharper warns about "possible multiple enumeration".
To avoid this, you would use var list = strings.Select(x => new Foo { A = x }).ToList(); to enumerate the sequence just once and store the results in an actual List<T>.
The problem is that you haven't called ToList method to materialize your LINQ query. When you call ToList as below:
var list = strings.Select(x => new Foo { A = x })
.ToList();
an in-memory collection of Foo objects would be created, whose property value A would have the value x. Essentially two new objects of type Foo would be created with the value of A to be "foo". Then you can loop through this list and modify the property value.
Please look at this fiddle
You are right that if will not going to be chnaged, then why compiler allow. but if you want to print without updating actual item in this scenario above code will helpful.
One thing you should know that, you can not modified the item of IEnumerable object.
you have to use List();
var strings = new List<string> { "foo", "foo" };
var list = strings.Select(x => new Foo { A = x }).ToList();
foreach (var item in list)
{
item.A = "bar";
}
foreach (var item in list)
{
Console.WriteLine(item.A);
}
I have two list
static List<dynamic> List1= new List<dynamic>();
list<string> List2
List1 is {Message='asdasd',Mobilenum=995955}
i want to remove all elements from List1 if the value in list2 is there in list1?
I have done this but it is not working
List1.RemoveAll(c => list2.ToList().Exists(n => n.Mobilenum== c.Values));
List1.RemoveAll(c => List2.Contains(c.Mobilenum));
But replace dynamic with the real type. Normally you don't need to use it. If it's an anonymous type and you have to pass this list around, consider to implement a new type with these properties.
First, create a type instead of using dynamic:
public class MyType
{
public string Message;
public string Mobilenum;
}
Then, you can do:
var List1 = new List<MyType>();
// ...build your list
var List2 = new List<string>();
// ...build your other list
var res = List1.Where(x => !List2.Contains(x.Mobilenum));
Avoid using Remove unless you're sure you want to throw away the information instead of just "filtering" it for a particular use.
Let's say I have such lists :
var firstList = new List<ofsometype>();
var secondList = new List<ofsomeanothertype>();
var thirdList = new List<anothertype>();
How can I make a list that accepts those lists? Like
var mainList = new List<???>();
mainList.Add(firstlist);
mainList.Add(secondlist);
mainList.Add(thirdlist);
Thanks.
I'd probably use a Dictionary collection instead :
var firstList = new List<ofsometype>();
var secondList = new List<ofsomeanothertype>();
var thirdlist = new List<anothertype>();
var listsDict = new Dictionary<Type, object>();
listsDict.Add(typeof(ofsometype), firstlist);
listsDict.Add(typeof(ofsomeanothertype), secondlist);
listsDict.Add(typeof(anothertype), thirdlist);
The advantage here is that it gives you the information regarding the type of a list. This could be used for two things :
Filter list for a certain type only
Know the type forList<object> later by simply using the key
P.S.
Depending on what the solution is and what you'd need to achieve you can use generics (if type is known) or dynamics - if type is unknown, but still a dynamic operation at run-time is required if compiler doesn't know the type.
If you want to add items from lists of different types, then they need to share either a common base class, or inherit from the same interface, e.g.
ofsometype : ISomeInterface
ofsomeanothertype: ISomeInterface
anothertype: ISomeInterface
var firstList = new List<ofsometype>();
var secondList = new List<ofsomeanothertype>();
var secondList = new List<anothertype>();
var mainList = new List<ISomeInterface>();
mainList.AddRange(firstlist);
mainList.AddRange(secondlist);
mainList.AddRange(thirdlist);
You'll be limited to accessing the members exposed by ISomeInterface when retrieving items from the list, unless you resort to casting/reflection.
This can also be achieved by adding them to a List<object>, but that gives you next to no information about what's contained in the list.
Simply use Object.
List<Object> or Object[] for array
var mainList = new List<List<Object>>();
mainList.Add(firstlist);
mainList.Add(secondlist);
mainList.Add(thirdlist);
I suggest this
var mainList = new List<Object[]>();
mainList.Add(firstlist.toArray());
mainList.Add(secondlist.toArray());
mainList.Add(thirdlist.toArray());
How can I sort a list of list?
persons.OrderBy(p => p.rate).ToList();
The list of list (persons) is declared like this:
public class Persons : List<Person> { }
When I'm trying to run the first statement I get an error:
Cannot convert from 'System.Collections.Generic.List' to
'Persons'
Is there a way to do this using LINQ?
Just because it inherits from a list doesn't mean you can use it like one.
Remember for everything else to see it as a list use interfaces (IList<T>). Then methods depending on IEnumerable, IList, ICollection, etc. can see that it's something it can deal with.
Otherwise, whose to say your Add() (As defined by IList) method isn't named AddPerson in your class?
You can achive it with that statement:
var persons = new Persons ();
persons.AddRange(persons.OrderBy(p => p.rate));
If you want to order all persons in all lists and huddle up them into one list:
var persons = new System.Collections.Generic.List<Persons>();
var trio = new Persons() { new Person(7), new Person(3), new Person(8) };
var pair = new Persons() { new Person(1), new Person(2) };
persons.Add(trio);
persons.Add(pair);
var ordered = persons.SelectMany(p => p).OrderBy(p => p.rate).ToList();
http://msdn.microsoft.com/en-us/library/system.linq.enumerable.selectmany.aspx
To achieve a SortBy behavior, you have to follow these three easy steps:
Store the old items (a. by storing the reference to the old list | b. by copying all entries of the old list into a new one)
Create an empty instance of your container class (a. by creating a new object of the needed type | b. by clearing the old list)
Fill your empty list with the entries while ordering them as you desire.
This little extension method should do the Trick:
public static void SortBy<TList, TItem, TOrder>(this TList source,
Func<TItem, TOrder> sortFunc)
where TList : List<TItem>
{
var l = source.ToList();
source.Clear();
source.AddRange(l.OrderBy(sortFunc));
}
I have the following situation:
I have a loop which could loop any amount of times. Within that loop I am calling a method which returns a List<CustomClass> After I have run through the loop I need to be able to compare all the List<CustomClass> items from each list and see which ones are common between all of them. In order to do this I have tried to put all the List<CustomClass> into another list: List<List<CustomClass> and then I need to use all of these to see which ones exist in all of them. I will be comparing on one property of my CustomClass (string Name)
This is what I have so far
public class CustomClass
{
public string name;
}
public List<CustomClass> SomeMethod()
{
List<List<CustomClass>> bigList = new List<List<CustomClass>>();
List<CustomClass> finalList = new List<CustomClass>();
for (int i=0;i<=5;i++)
{
List<List<CustomClass>> newList = GetNewList();
bigList.Add(newList);
}
//I now need to compare everything in bigList and create a new list with all common
//items in the list of bigList.
return finalList ;
}
public List<CustomClass> GetNewList()
{
List<CustomClass> newList = new List<CustomClass>();
for (int i=0;i<=5;i++)
{
CustomClass newClass = new CustomClass();
newClass.name = "some name";
newList.Add(newClass);
}
return newList;
{
I hope this makes sense. Any help on this is much appreciated.
Thanks
Edit
For example in List<List<CustomClass>> each List<CustomClass> contains a CustomClass with name set to "Pete", I then want to create a CustomClass with name set to "Pete" and add it to the final list.
see which ones are common between all of them
Use the Intersect extension method:
var common = list1.Intersect(list2);
Note that for this to work, you should either:
override Equals and GetHashCode in CustomClass
make CustomClass implement IEquatable<CustomClass>
provide Intersect with a custom comparer that implements IEqualityComparer<CustomClass>