convert a generic list to ISet - c#

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

Related

Initialize an IEnumerable<T> to a new List<T>

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

KellermanSoftware CompareNetObjects, comparing collections of different types

I am using CompareNetObjects for automated testing of my system. This has been useful in ensuring performance optimizations do not change the expected behavior of the system, and ensuring errors are not introduced.
When I have a collection that is declared in an abstract way, I expect to have the contents compared, not the collection itself; however, I do not see an option to enable this.
Class:
public class MustBeCorrect
{
public string Name { get; set; }
IEnumerable<string> Items { get; set; }
}
Test:
[Fact] void IsCorrect()
{
var obj1 = new MustBeCorrect
{
Name = "Kitty",
Items = new string[]
{
"Collar",
"Bell"
}
};
var obj2 = new MustBeCorrect
{
Name = "Kitty",
Items = new List<string>
{
"Collar",
"Bell"
}
};
comparer.Compare(obj1, obj2); // False!
}
The above two objects compare as not equal, even though the only difference between the two objects is one uses an array, and the other uses a list. In terms of my contract, however, these two seem as they should be considered equal to me.
How can I configure the comparison options to only compare the contents of collections, rather than the collection itself?
There does not exist a way to do what you want specifically for collections.
However, there is an option you can set called IgnoreObjectTypes in the ComparisonConfig. It is default to false, but if you set it to true, it should give you the behavior you desire for your collections.
Be aware, this will ignore object types for all comparisons.
This is the only way I found to make it work so far.
My solution consists in implementing a Custom comparer that ignores the generic argument of the collection when comparing IEnumerables.
However, the drawback of this approach is that you lose the granularity of the returned result.Differences: if two lists have different elements, it won't tell you exactly how and which elements are different.
If someone could identify a way to implement this in the Custom Comparer, that'd be great.
public class OnlyIEnumContents : BaseTypeComparer
{
public OnlyIEnumContents(RootComparer rootComparer) : base(rootComparer)
{
}
public OnlyIEnumContents() : this(RootComparerFactory.GetRootComparer())
{
}
public override bool IsTypeMatch(Type type1, Type type2)
{
if (typeof(IEnumerable).IsAssignableFrom(type1) && typeof(IEnumerable).IsAssignableFrom(type2))
return true;
return type1 == type2;
}
public override void CompareType(CompareParms parms)
{
var ienum1 = parms.Object1 as IEnumerable;
var ienum2 = parms.Object2 as IEnumerable;
if (ienum1 != null && ienum2 != null)
{
List<object> list1 = new List<object>();
List<object> list2 = new List<object>();
foreach (var item in ienum1)
list1.Add(item);
foreach (var item in ienum2)
list2.Add(item);
// Compare the lists.
// Because all the list elements were boxed in a System.Object,
// this only returns the differences between the single elements.
CompareLogic compareLogic = new CompareLogic();
ComparisonResult result = compareLogic.Compare(list1, list2);
// This is where granularity is lost.
// The official documentation https://github.com/GregFinzer/Compare-Net-Objects/wiki/Custom-Comparers
// points that we should return `AddDifference(parms)`,
// however I don't know how to get `parms` from a given `result` object.
// Returning a single difference for the entire lists.
if (!result.AreEqual)
AddDifference(parms);
}
}
}
And then to use it:
CompareLogic compareLogic = new CompareLogic();
compareLogic.Config.CustomComparers.Add(new OnlyIEnumContents());
ComparisonResult result = compareLogic.Compare(obj1, obj2);

Why does a combination of object and collection initializers use Add method?

The following combination of object and collection initializers does not give compilation error, but it is fundamentally wrong (https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers#examples), because the Add method will be used in the initialization:
public class Foo
{
public List<string> Bar { get; set; }
}
static void Main()
{
var foo = new Foo
{
Bar =
{
"one",
"two"
}
};
}
So you'll get NullReferenceException. What is the reason for making such an unsafe decision while developing the syntax of the language? Why not to use initialization of a new collection for example?
First, it's not only for combination of object and collection initializers. What you are referring here is called nested collection initializers, and the same rule (or issue by your opinion) applies to nested object initializers. So if you have the following classes:
public class Foo
{
public Bar Bar { get; set; }
}
public class Bar
{
public string Baz { get; set; }
}
and you use the following code
var foo = new Foo
{
Bar = { Baz = "one" }
};
you'll get the same NRE at runtime because no new Bar will be created, but attempt to set Baz property of the Foo.Bar.
In general the syntax for object/collection initializer is
target = source
where the source could be an expression, object initializer or collection initializer. Note that new List<Bar> { … } is not a collection initializer - it's an object creation expression (after all, everything is an object, including collection) combined with collection initializer. And here is the difference - the idea is not to omit the new, but give you a choice to either use creation expression + object/collection initializer or only initializers.
Unfortunately the C# documentation does not explain that concept, but C# specification does that in the Object Initializers section:
A member initializer that specifies an object initializer after the equals sign is a nested object initializer, i.e. an initialization of an embedded object. Instead of assigning a new value to the field or property, the assignments in the nested object initializer are treated as assignments to members of the field or property. Nested object initializers cannot be applied to properties with a value type, or to read-only fields with a value type.
and
A member initializer that specifies a collection initializer after the equals sign is an initialization of an embedded collection. Instead of assigning a new collection to the target field, property or indexer, the elements given in the initializer are added to the collection referenced by the target.
So why is that? First, because it clearly does exactly what you are telling it to do. If you need new, then use new, otherwise it works as assignment (or add for collections).
Other reasons are - the target property could not be settable (already mentioned in other answers). But also it could be non creatable type (e.g. interface, abstract class), and even when it is a concrete class, except it is a struct, how it will decide that it should use new List<Bar> (or new Bar in my example) instead of new MyBarList, if we have
class MyBarList : List<Bar> { }
or new MyBar if we have
class MyBar : Bar { }
As you can see, the compiler cannot make such assumptions, so IMO the language feature is designed to work in the quite clear and logical way. The only confusing part probably is the usage of the = operator for something else, but I guess that was a tradeoff decision - use the same operator = and add new after that if needed.
Take a look at this code and the output of it due to the Debug.WriteLine():
public class Foo
{
public ObservableCollection<string> _bar = new ObservableCollection<string>();
public ObservableCollection<string> Bar
{
get
{
Debug.WriteLine("Bar property getter called");
return _bar;
}
set
{
Debug.WriteLine("Bar allocated");
_bar = value;
}
}
public Foo()
{
_bar.CollectionChanged += _bar_CollectionChanged;
}
private void _bar_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Debug.WriteLine("Item added");
}
}
public MainWindow()
{
Debug.WriteLine("Starting..");
var foo = new Foo
{
Bar =
{
"one",
"two"
}
};
Debug.WriteLine("Ending..");
}
The output is:
Starting..
Bar property getter called
Item added
Bar property getter called
Item added
Ending..
For you questions:
What is the reason for making such an unsafe decision while developing the syntax of the language? Why not to use initialization of a new collection for example?
Answer:
As you can see the intention of the designer of that feature was not to reallocate the collection but rather to help you add items to it more easily considering that you manage your collection allocation by yourself.
Hope this clear things out ;)
Consider the following code:
class Program
{
static void Main()
{
var foo = new Foo
{
Bar =
{
"one",
"two"
}
};
}
}
public class Foo
{
public List<string> Bar { get; set; } = new List<string>();
}
The compiler does not know whether you already created a new list instance within the class constructor (or in another method).
Recall that collection initializer is a series of calls to Add method on an existing collection!
See also:
Custom Collection Initializers
Also note that this initializer applies to a collection that was exposed as a property. Hence the collection initializer is possible as part of the outer object initializer (the Foo object in your example).
However, if it was a simple variable, the compiler would not let you to intialize the collection this way. Here is an example:
List<string> list =
{
"one",
"two"
};
This will throws a compilation error.
As last example, the output of the following code will be: "one, two, three, four, ". I think that now you understand why.
Pay attention to the list static instance, as well as to the private modifier in the "set" of the Bar property, which does not matters because the initializer just calls the Add method, which is accessible even when the Bar "set" is private.
class Program
{
static void Main()
{
var foo1 = new Foo
{
Bar =
{
"one",
"two"
}
};
var foo2 = new Foo
{
Bar =
{
"three",
"four"
}
};
PrintList(foo1.Bar);
}
public static void PrintList(List<string> list)
{
foreach (var item in list)
{
Console.Write(item + ", ");
}
Console.WriteLine();
}
}
public class Foo
{
private static readonly List<string> _bar = new List<string>();
public List<string> Bar { get; private set; } = _bar;
}
I believe the key thing to understand here is that there are two syntactic sugar flavors at play (or at least, there should be):
Object Initialization
Collection Initialization
Take away the List for a moment and look at the field as an object:
public class Foo
{
public object Bar { get; set; }
}
When using Object Initialization, you assign an object (or null):
var foo = new Foo()
{
Bar = new object(); //or Bar = null
}
Now, let's go back to your original example and slap Collection Initialization on top of this. This time around, the compiler realizes this property implements IEnumerable and the array you have provided is of the right type, so it attempts to call the Add method of the interface. It must first go looking for the object, which in your case is null because you haven't initialized it internally. If you debug through this, you will find that the getter gets called and returns null, hence the error.
The correct way of mixing both features then would be for you to assign a new object that you initialize with your values:
var foo = new Foo()
{
Bar = new List<string>(){ "one", "two" }
};
If you debug this version, you will find that the setter is called instead, with the new instance you initialized.
Alternatively, you can initialize your property internally:
public List<string> Bar { get; set; } = new List<string>();
If you debug this version, you will find that the property is first initialized with a value and your version of the code then executes without error (by calling the getter first):
var foo = new Foo()
{
Bar = {"one", "two"}
};
To illustrate the syntactic sugar aspect, Collection Initialization only works within the confines of a constructor calling statement:
List<string> bar = {"one", "two" }; //ERROR: Can only use array initializer expressions to assign to array types. Try using a new expression instead.
List<string> bar = new[] { "one", "two" }; //ERROR: Cannot implicitly convert type 'string[]' to 'System.Collections.Generic.List<string>'
List<string> bar = new List<string>() { "one", "two" }; //This works!
If you wish to allow initialization like in your original example, then the expectation is that the variable will be set to an instance before the Add method can be called. This is true whether you use syntactic sugar or not. I could just as well run into the same error by doing this:
var foo = new Foo();
foo.Bar.Add("one");
So you may want to initialize the variable in order to cover all bases, unless of course a null value has a semantic meaning in your application.

How to assign List<Bear> or List<Goat> to List<IAnimal>

I have an interface (IAnimal) which is implemented by two classes, Bear and Goat.
At runtime, I may end up with a List of Bears, Or Goats, but whichever it is they need to be assigned to property IEnumerable<IAnimal>
This works, as IEnumerable is co-variant.
However, I now need to remove items from IEnumerable<IAnimal> which of course does not work.
What do I need to do to be able to remove items?
Here is the working sample:
interface IAnimal {}
public class Bear : IAnimal {}
public class Goat : IAnimal {}
class Program
{
public static IEnumerable<IAnimal> CouldBeBearsOrGoats { get; set; }
static void Main(string[] args) {
var list = new List<int>() {1, 2, 3};
var bears = from l in list select new Bear();
var goats = from l in list select new Goat();
CouldBeBearsOrGoats = bears;
CouldBeBearsOrGoats = goats;
//How do I now remove an item?
}
}
If I change CouldBeBearsOrGoats to a List, then I can remove items, but I can no longer assign either type.
public static List<IAnimal> CouldBeBearsOrGoats { get; set; }
The list is going to be very long, and so I do not want to just make a copy of the list and work with a copy. What I am doing is processing each item in the list and then removing it until the list is empty.
Since your source data is anyway IEnumerable, you have to convert it to List to add/remove elements.
List<IAnimal> ListOfAnimals1 = bears.Cast<IAnimal>().ToList();
List<IAnimal> ListOfAnimals2 = goats.Cast<IAnimal>().ToList();
A posibility is to add a Cast call in your LINQ query, so that it converts the IEnumerable<Goat> to an IEnumerable<IAnimal> (which actually creates a new iterator with each element casted).
var bears = (from l in list select new Bear()).Cast<IAnimal>().ToList();
var goats = (from l in list select new Goat()).Cast<IAnimal>().ToList();
Now both bears and goats are enumerables of IAnimal which you can operate on them.
I don't think there's an easy way to do that using only strongly typed collections1, since there is no covariant collection interface that exposes a Remove method...
I see 2 possible solutions:
use the non-generic ICollection interface, that is implemented by List<T>:
var collection = (ICollection) CouldBeBearsOrGoats;
collection.Remove(whatever);
The drawback is that a collection that implements ICollection<T> might not implement ICollection...
use dynamic:
dynamic collection = CouldBeBearsOrGoats
collection.Remove(whatever);
But it's probably slower than the previous approach.
1 assuming you don't want to change the actual type of the collections by casting items to IAnimal

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