Initialize an IEnumerable<T> to a new List<T> - c#

I have a class like this:
public class ItemList
{
[JsonProperty("items")]
public IEnumerable<Item> Items { get; set; }
}
And I want to initialize empty list, like this:
var newItemList = new ItemList
{
Items = new List<Item>()
};
But the Items remains an IEnumerable and I can't use Add or other methods of a list.

Why not declare it as a list
public class ItemList
{
[JsonProperty("items")]
public List<Item> Items { get; set; }
}
List is IEnumerable by extention, so it would make sense to declare it as a list and have all the methods in place.
Since you already declared is public IEnumerable<Item> Items { get; set; } it will not change.
You can do this:
Items = new List<Item>();
and even
ItemList itemlist = new itemlist();
itemlist.Items = new List<Item>();
((List<Item>)itemlist.Items).Add(new Item());
But ((List<Item>)itemlist.Items).Add(new Item()); is not safe. It will work when you initialize as a list, but it will lead to a runtime exception if you try to cast from some other IEnumerable type.

Having IEnumerable allows you to accomplish one of the SOLID principles that say that you must rely on abstraction rather than on concrete classes. Meaning that you can store whatever implementation of IEnumerable within that property (List, HashSet, etc ...).
You have to convert IEnumerable to List If you want to use the Add method implemented by the List class
var myList = newItemList.ToList<T>();
myList.Add(new T());
where T is your concrete class.

You can use either of the below two options.
You can use List Initializer like below
var itemList = new ItemList() {
Items = new List<Item>() {
new Item() { Name = "One" },
new Item() { Name = "Two" }
}
};
You can initialize the list fully and then assign it to the Items
Much better approach would be to use a Builder pattern which would help in constructing the ItemList as described at https://code-maze.com/fluent-builder-recursive-generics/

Sure you can, just cast it:
(Items as List<Item>).Add(someItem);
It's gonna get pretty boring casting it all the time, perhaps:
public class ItemList
{
private List<Item> _items - new List<Item>;
[JsonProperty("items")]
public IEnumerable<Item> Items { get => _items; private set => _items = value as List<string>; }
}
Then inside the class you can use _items.
I recommend you make that setter private and set the items to be a List internally to the class; the cast is needed on the set, but if someone else passes in an IEnumerable that isn't a List it will cause the items collection to be set to null.
If you're going to make the decision that external classes will see an IEnumerable but you're going to have it be a List, then you shouldn't give anyone using your class the opportunity to change it to something that's not a List..
If you're only ever going to set the list once (never change it for a new instance) e.g. in the constructor, then you can make the property readonly instead

Related

is there a way to make a list of two differnt type

I am trying to make a list which is used to store data source of a data grid view
but the type of data source of data grid view is either "string" or "decimal"
I made this code
List<string> list1 = (List<string>)DataGridView.Datasource;
List<decimal> list2 = (List<decimal>)DataGridView.Datasource;
Two different type of list but I want to do this by declaring only one list
please help me..
use List<object> or worse ArrayList (Don't use ArrayList please).
List<object> list = (List<object>)DataGridView.datasource;
You can also look into List<dynamic>
List<dynamic> list = new List<dynamic>();
list.Add(1);
list.Add("ABCD");
list.Add(1f);
foreach (var item in list)
{
Console.WriteLine(item.GetType());
}
and the output would be:
System.Int32
System.String
System.Single
(Not really sure if casting the DataSource from the GridView is possible for List<dynamic>)
If you need to you can cast the data source to IList (the non-generic version).
IList data = (IList)DataGridView.Datasource;
This will allow you to access the items in the list as object types.
Another option would be to simply check the type of the list and act accordingly:
if(DataGridView.Datasource is List<string>)
{
List<string> list = (List<string>)DataGridView.Datasource;
}
else
{
List<decimal> list = (List<decimal>)DataGridView.Datasource;
}
This would be what you would do if you needed to have the objects typed as either a string or decimal, and couldn't work with them just as objects.
If DataGridView.datasource is a List<decimal> then you will need to instantiate a new list and add each object manually:
List<object> myList = new List<object>();
foreach(var item in DataGridView.datasource)
{
myList.Add(item);
}
But as DanielMann says, you really should define a proper class to handle your two types of object, rather than just shoehorning them into a List<object>...
Since no one else mentioned this yet...
There is also a CompositeCollection that you can use to store different types of objects in one IList compatible collection.
public class MyObject()
{
public string SomeData { get; set; }
public int SomeOtherData { get; set; }
}
public class MyOtherObject()
{
public Guid ID { get; set; }
public object Foo { get; set; }
}
public class Main()
{
private List<MyObject> objects = new List<MyObject>();
private List<MyOtherObject> moreObjects = new List<MyOtherObject>();
public CompositeCollection TheCollection { get; private set; }
public Main()
{
//mock adding data to the list
objects.Add( ... );
moreObjects.Add ( ... );
//Build the composite collection
TheCollection = new CompositeCollection
{
new CollectionContainer {Collection = objects},
new CollectionContainer {Collection = moreObjects}
};
}
}
List<object> genericList = (List<object>)DataGridView.datasource;
would it solve the issue?
Here is sample conversion using LINQ.
List<decimal> dList = new List<decimal>();
List<object> oList = new List<object>();
oList = dList.Select(x => (object)x).ToList<object>();

convert a generic list to ISet

Has anyone had to assign a list to an ISet? How do I go about and do this?
Say I have the class
class Foo
{
ISet<Item> Items { get; set; }
}
Now, I want to do the following:
var foo = new Foo() { Items = new List<Item>() { new Item() } }
List<Item> myList = ...
foo.Items = new HashSet<Item>( myList );
Keep in mind that a Set, unlike a List, must contain every element exactly once. Therefore, if myList contains multiple copies of some elements, all those copies, except one, will not make it into the set.
Equality of elements (for detecting multiple copies) is defined by the Equals and GetHashCode methods. If you would like to use a different definition of equality, you can use the overload of HashSet constructor that takes an IEqualityComparer<Item>.
List<T> doesn't implement the ISet<T> interface… So, this isn't possible.
The only classes that implement ISet<T> are HashSet<T> and SortedSet<T>.
The closest you could get would be (if you cut out the unnecessary List object in between):
var foo = new Foo { Items = new HashSet<Item> { new Item() } };

Casting class to interface and back

I have the following:
public interface ICartItem
{
string Name { get; set; }
}
public class CartItem : ICartItem
{
public string Name { get; set; }
}
I then create a List and cast it to an interface:
IList<CartItem> items = new List<CartItem>()
{
new CartItem() { Name = "MyItem" }
};
IList<ICartItem> cartItems = items.Cast<ICartItem>().ToList();
Is there a way to cast it back again like illustrated below?
IList<CartItem> newList = cartItems as IList<CartItem>;
Do you need a copy of the list?
If yes, and you are sure that there are only CartItems within the list you can do it with
IList<CartItem> newList = cartItems.Cast<CartItem>().ToList();
But i think you'd like it a little more robust. In that case you can try it with
cartItems.Where(item => item as CartItem != null).Cast<CartItem>().ToList();
But i think you need to create a new list. I can't think of a way to work on the same with an IList interface (IEnumerable<T> works as shown above).
This is not a logical issue because you cannot make sure that all the items in the 'cartItems' list can be casting to 'CartItem' type.
Basically, the answer is no, IList<ICartItem> cannot be cast back to IList since CartItem is not the only type that might implement ICartItem. The cast cannot be type checked by the compiler since it does't know what will be inside the list at runtime.
In C# 4, you can do this:
IEnumerable<CartItem> items = new List<CartItem>
{
new CartItem() { Name = "MyItem" }
};
IEnumerable<ICartItem> cartItems = items;
(i.e. no need for the use of .Cast<ICartItem>().ToList())
Note that the interface is IEnumerable<> and not IList<> since only some interfaces were made covariant in C# 4 (the full list cn be found here: http://msdn.microsoft.com/en-us/library/dd233059.aspx).
However, even in C# 4, adding the following line will cause the compiler to fail:
IEnumerable<CartItem> newList = cartItems;

Adding a list item within another list

Ok I have a class similar to the following...
public class Order
{
private Guid id;
[DataMember]
public Guid ID
{
get { return id; }
set { id = value; }
}
private List<Items> orderItems;
[DataMember]
public List<Items> OrderItems
{
get { return orderItems; }
set { orderItems= value; }
}
}
public class Items
{
private string itemName;
[DataMember]
public string ItemName
{
get { return itemName; }
set { itemName = value; }
}
}
When I reference in my code I have a method that takes in an "Order" list as the parameter.
ACME.Order newOrder = new ACME.Order();
ACME.Items newItems = new ACME.Items();
newOrder.ID = xxx
newItems.ItemName = xxx
SendOrderWithItemsFunction(newOrder)
The above works fine however I don't have an add function for my items so that I can do something like the following
newOrder.Items.Add(newItem);
and
newOrder.Items = newItems
will not work because it says that it can not implicitly convert newOrder.Items to newItems[].
What am Missing?
I think I might be missing something, but newOrder.OrderItems.Add(newItem) should work just fine, according to waht you have in your post.
Just some other nitpick things:
The pluralization of the "Items" class is wierd, if it is only a single Item. This is probably the reason that it looked "ok" to assign a single item to a List property.
You may have cut it out of your post, but every class that is being serialized by WCF must be marked as a "DataContract", not just the members of the class.
When initializing objects like this, I think it makes it a lot cleaer to use Type Initializers:
var NewOrder = new ACME.Order{
ID = xxx,
OrderItems = new List<ACME.Item>
{
new ACME.Item{
ItemName = xxx
}
}
};
What you do have is an add function in your Order.OrderItems property:
newOrder.OrderItems.Add(newItem);
you can even add a whole list of items to your OrderItems:
var someList = new List<Items>();
//populate someList here
newOrder.OrderItems.AddRange(someList);
You should be able to do:
newOrder.OrderItems.Add(newItem);
If your newItems[] is an array, you need to do this:
newOrder.OrderItems.AddRange(newItem.ToList<Items>());
You have declared newItems as an ACME.Items type, but the OrderItems property of your Order class is a List<Items>. Those types are not assignable from one to the other directly. So, an assignment of newOrder.OrderItems = newItems is like trying to sayList<Items> = Items. That isn't possible based on the classes you outlined above. Instead, you will need to add to the list.
When you have a list within a list, and the Add() method is missing, a workaround is to make a new list, add the items, then set the inner list to the new list. Instead of:
outerList.innerList.Add(item)
..use..
var newList = new List<ItemType>();
newList.Add(item);
outerList.innerList = newList;

Correct usage of properties when dealing with a collection

I am wondering what is the best way to use properties when dealing with collections.
For example I have a class Foo and I want to have a list of that class stored. Which of the following should be used:
private List<Foo> myList;
private List<Foo> myOtherList = new List<Foo>();
now for the property:
public List<Foo> ListOfFoo
{
get
{
return myList;
}
set
{
myList= new List<Foo>(value);
}
}
Or should the set just be to the value?
public List<Foo> ListOfFoo
{
get
{
return myList;
}
set
{
myList= value;
}
}
Choose
private List<Foo> myOtherList = new List<Foo>();
becuse the other just declares a reference (which is set to null), the sample above declares a reference to a list, creates a list and assignes that new list to the reference.
Choose
public List<Foo> ListOfFoo
{
get { return myList; }
set { myList= new List<Foo>(value); }
}
When you want myList to NOT refelect any changes that happen to the list after it is assigned to myList e.g.
List<string> myFirstList = new List<string>();
myFirstList.Add("Hello");
myFirstList.Add("World");
List<string> mySecondList = new List<string>(myFirstList);
// mySecondList now contains Hello & world
myFirstList.Add("Boyo");
// myFrist List now contains Hello, world & Boyo
// mySecondList still contains Hello & world
Choose
public List<Foo> ListOfFoo
{
get { return myList; }
set { myList= value; }
}
When you want both references to point to the same object e.g.
List<string> myFirstList = new List<string>();
myFirstList.Add("Hello");
myFirstList.Add("World");
List<string> mySecondList = myFirstList;
// mySecondList now contains Hello & world
myFirstList.Add("Boyo");
// myFrist List now contains Hello, world & Boyo
// mySecondList "also" contains Hello, world & Boyo
The "also" above is in quotes, because actually, there is only one list, and both my first and my second point to the same list.
Generally you don't want to use properties of a rich type like List<T> (normally one would use Collection<T>), and generally properties of a collection type are read-only - the collection itself can be modified with methods like Clear, Add etc., and this is normally sufficient.
For example:
class Foo
{
Collection<Bar> _bars = new Collection<Bar>();
public Collection<Bar> Bars { get { return _bars; } }
}
This also leaves you open to validate modifications to the collection by implementing a descendant of Collection<T> and overriding the InsertItem, SetItem etc. methods.
It depends.
When the first style is used, you create a copy of the list, which is generally unnecessary. .Net convention is for the setter to assign the reference to the property. This is why I would lean towards the second option.
However, if you are intending for the copy operation to take place, the first option is what you are looking for.
Generally, expose only an Interface (ICollection, IList or similar), and make it readonly:
private IList<Foo> m_list = new List<Foo>();
public IList<Foo> List {get { return m_list; } }
Advantage: You can modify the implementation, e.g. switch from a List to an Observable List. You might need to make the m_list member of the concrete type rather than the interface, e.g. to use additional funcitonality.
With an settable external list, you run into a few problems. However, there are some cases where this is needed:
the data can be created externally, and is potentially large, and changes frequently (e.g. tens of thousands of items)
the external list should be shared between different instances
Why not use the IEnumerator-Interface on the class and if you have to use a setter, use a certain method.
This way you are hiding the actual List-Implementation as well.
class FooBar : IEnumerator
{
private Collection<Foo> col;
public IEnumarator GetEnumerator()
{
return col.GetEnumerator();
}
public void SetList(Collection col)
{
this.col= col; // you can also make this more general and convert the parameter so it fits your listimpl.
}
}
class Clazz
{
private void WhatEver(){
FooBar foobar = new FooBar();
...
foreach(Foo f in foobar)
{...}
}
}

Categories

Resources