Sorting an IList in C# - c#

So I came across an interesting problem today. We have a WCF web service that returns an IList. Not really a big deal until I wanted to sort it.
Turns out the IList interface doesn't have a sort method built in.
I ended up using the ArrayList.Adapter(list).Sort(new MyComparer()) method to solve the problem but it just seemed a bit "ghetto" to me.
I toyed with writing an extension method, also with inheriting from IList and implementing my own Sort() method as well as casting to a List but none of these seemed overly elegant.
So my question is, does anyone have an elegant solution to sorting an IList

You can use LINQ:
using System.Linq;
IList<Foo> list = new List<Foo>();
IEnumerable<Foo> sortedEnum = list.OrderBy(f=>f.Bar);
IList<Foo> sortedList = sortedEnum.ToList();

This question inspired me to write a blog post: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/
I think that, ideally, the .NET Framework would include a static sorting method that accepts an IList<T>, but the next best thing is to create your own extension method. It's not too hard to create a couple of methods that will allow you to sort an IList<T> as you would a List<T>. As a bonus you can overload the LINQ OrderBy extension method using the same technique, so that whether you're using List.Sort, IList.Sort, or IEnumerable.OrderBy, you can use the exact same syntax.
public static class SortExtensions
{
// Sorts an IList<T> in place.
public static void Sort<T>(this IList<T> list, Comparison<T> comparison)
{
ArrayList.Adapter((IList)list).Sort(new ComparisonComparer<T>(comparison));
}
// Sorts in IList<T> in place, when T is IComparable<T>
public static void Sort<T>(this IList<T> list) where T: IComparable<T>
{
Comparison<T> comparison = (l, r) => l.CompareTo(r);
Sort(list, comparison);
}
// Convenience method on IEnumerable<T> to allow passing of a
// Comparison<T> delegate to the OrderBy method.
public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> list, Comparison<T> comparison)
{
return list.OrderBy(t => t, new ComparisonComparer<T>(comparison));
}
}
// Wraps a generic Comparison<T> delegate in an IComparer to make it easy
// to use a lambda expression for methods that take an IComparer or IComparer<T>
public class ComparisonComparer<T> : IComparer<T>, IComparer
{
private readonly Comparison<T> _comparison;
public ComparisonComparer(Comparison<T> comparison)
{
_comparison = comparison;
}
public int Compare(T x, T y)
{
return _comparison(x, y);
}
public int Compare(object o1, object o2)
{
return _comparison((T)o1, (T)o2);
}
}
With these extensions, sort your IList just like you would a List:
IList<string> iList = new []
{
"Carlton", "Alison", "Bob", "Eric", "David"
};
// Use the custom extensions:
// Sort in-place, by string length
iList.Sort((s1, s2) => s1.Length.CompareTo(s2.Length));
// Or use OrderBy()
IEnumerable<string> ordered = iList.OrderBy((s1, s2) => s1.Length.CompareTo(s2.Length));
There's more info in the post: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/

How about using LINQ To Objects to sort for you?
Say you have a IList<Car>, and the car had an Engine property, I believe you could sort as follows:
from c in list
orderby c.Engine
select c;
Edit: You do need to be quick to get answers in here. As I presented a slightly different syntax to the other answers, I will leave my answer - however, the other answers presented are equally valid.

You're going to have to do something like that i think (convert it into a more concrete type).
Maybe take it into a List of T rather than ArrayList, so that you get type safety and more options for how you implement the comparer.

The accepted answer by #DavidMills is quite good, but I think it can be improved upon. For one, there is no need to define the ComparisonComparer<T> class when the framework already includes a static method Comparer<T>.Create(Comparison<T>). This method can be used to create an IComparison on the fly.
Also, it casts IList<T> to IList which has the potential to be dangerous. In most cases that I have seen, List<T> which implements IList is used behind the scenes to implement IList<T>, but this is not guaranteed and can lead to brittle code.
Lastly, the overloaded List<T>.Sort() method has 4 signatures and only 2 of them are implemented.
List<T>.Sort()
List<T>.Sort(Comparison<T>)
List<T>.Sort(IComparer<T>)
List<T>.Sort(Int32, Int32, IComparer<T>)
The below class implements all 4 List<T>.Sort() signatures for the IList<T> interface:
using System;
using System.Collections.Generic;
public static class IListExtensions
{
public static void Sort<T>(this IList<T> list)
{
if (list is List<T> listImpl)
{
listImpl.Sort();
}
else
{
var copy = new List<T>(list);
copy.Sort();
Copy(copy, 0, list, 0, list.Count);
}
}
public static void Sort<T>(this IList<T> list, Comparison<T> comparison)
{
if (list is List<T> listImpl)
{
listImpl.Sort(comparison);
}
else
{
var copy = new List<T>(list);
copy.Sort(comparison);
Copy(copy, 0, list, 0, list.Count);
}
}
public static void Sort<T>(this IList<T> list, IComparer<T> comparer)
{
if (list is List<T> listImpl)
{
listImpl.Sort(comparer);
}
else
{
var copy = new List<T>(list);
copy.Sort(comparer);
Copy(copy, 0, list, 0, list.Count);
}
}
public static void Sort<T>(this IList<T> list, int index, int count,
IComparer<T> comparer)
{
if (list is List<T> listImpl)
{
listImpl.Sort(index, count, comparer);
}
else
{
var range = new List<T>(count);
for (int i = 0; i < count; i++)
{
range.Add(list[index + i]);
}
range.Sort(comparer);
Copy(range, 0, list, index, count);
}
}
private static void Copy<T>(IList<T> sourceList, int sourceIndex,
IList<T> destinationList, int destinationIndex, int count)
{
for (int i = 0; i < count; i++)
{
destinationList[destinationIndex + i] = sourceList[sourceIndex + i];
}
}
}
Usage:
class Foo
{
public int Bar;
public Foo(int bar) { this.Bar = bar; }
}
void TestSort()
{
IList<int> ints = new List<int>() { 1, 4, 5, 3, 2 };
IList<Foo> foos = new List<Foo>()
{
new Foo(1),
new Foo(4),
new Foo(5),
new Foo(3),
new Foo(2),
};
ints.Sort();
foos.Sort((x, y) => Comparer<int>.Default.Compare(x.Bar, y.Bar));
}
The idea here is to leverage the functionality of the underlying List<T> to handle sorting whenever possible. Again, most IList<T> implementations that I have seen use this. In the case when the underlying collection is a different type, fallback to creating a new instance of List<T> with elements from the input list, use it to do the sorting, then copy the results back to the input list. This will work even if the input list does not implement the IList interface.

try this **USE ORDER BY** :
public class Employee
{
public string Id { get; set; }
public string Name { get; set; }
}
private static IList<Employee> GetItems()
{
List<Employee> lst = new List<Employee>();
lst.Add(new Employee { Id = "1", Name = "Emp1" });
lst.Add(new Employee { Id = "2", Name = "Emp2" });
lst.Add(new Employee { Id = "7", Name = "Emp7" });
lst.Add(new Employee { Id = "4", Name = "Emp4" });
lst.Add(new Employee { Id = "5", Name = "Emp5" });
lst.Add(new Employee { Id = "6", Name = "Emp6" });
lst.Add(new Employee { Id = "3", Name = "Emp3" });
return lst;
}
**var lst = GetItems().AsEnumerable();
var orderedLst = lst.OrderBy(t => t.Id).ToList();
orderedLst.ForEach(emp => Console.WriteLine("Id - {0} Name -{1}", emp.Id, emp.Name));**

Found this thread while I was looking for a solution to the exact problem described in the original post. None of the answers met my situation entirely, however. Brody's answer was pretty close. Here is my situation and solution I found to it.
I have two ILists of the same type returned by NHibernate and have emerged the two IList into one, hence the need for sorting.
Like Brody said I implemented an ICompare on the object (ReportFormat) which is the type of my IList:
public class FormatCcdeSorter:IComparer<ReportFormat>
{
public int Compare(ReportFormat x, ReportFormat y)
{
return x.FormatCode.CompareTo(y.FormatCode);
}
}
I then convert the merged IList to an array of the same type:
ReportFormat[] myReports = new ReportFormat[reports.Count]; //reports is the merged IList
Then sort the array:
Array.Sort(myReports, new FormatCodeSorter());//sorting using custom comparer
Since one-dimensional array implements the interface System.Collections.Generic.IList<T>, the array can be used just like the original IList.

Useful for grid sorting this method sorts list based on property names. As follow the example.
List<MeuTeste> temp = new List<MeuTeste>();
temp.Add(new MeuTeste(2, "ramster", DateTime.Now));
temp.Add(new MeuTeste(1, "ball", DateTime.Now));
temp.Add(new MeuTeste(8, "gimm", DateTime.Now));
temp.Add(new MeuTeste(3, "dies", DateTime.Now));
temp.Add(new MeuTeste(9, "random", DateTime.Now));
temp.Add(new MeuTeste(5, "call", DateTime.Now));
temp.Add(new MeuTeste(6, "simple", DateTime.Now));
temp.Add(new MeuTeste(7, "silver", DateTime.Now));
temp.Add(new MeuTeste(4, "inn", DateTime.Now));
SortList(ref temp, SortDirection.Ascending, "MyProperty");
private void SortList<T>(
ref List<T> lista
, SortDirection sort
, string propertyToOrder)
{
if (!string.IsNullOrEmpty(propertyToOrder)
&& lista != null
&& lista.Count > 0)
{
Type t = lista[0].GetType();
if (sort == SortDirection.Ascending)
{
lista = lista.OrderBy(
a => t.InvokeMember(
propertyToOrder
, System.Reflection.BindingFlags.GetProperty
, null
, a
, null
)
).ToList();
}
else
{
lista = lista.OrderByDescending(
a => t.InvokeMember(
propertyToOrder
, System.Reflection.BindingFlags.GetProperty
, null
, a
, null
)
).ToList();
}
}
}

Here's an example using the stronger typing. Not sure if it's necessarily the best way though.
static void Main(string[] args)
{
IList list = new List<int>() { 1, 3, 2, 5, 4, 6, 9, 8, 7 };
List<int> stronglyTypedList = new List<int>(Cast<int>(list));
stronglyTypedList.Sort();
}
private static IEnumerable<T> Cast<T>(IEnumerable list)
{
foreach (T item in list)
{
yield return item;
}
}
The Cast function is just a reimplementation of the extension method that comes with 3.5 written as a normal static method. It is quite ugly and verbose unfortunately.

In VS2008, when I click on the service reference and select "Configure Service Reference", there is an option to choose how the client de-serializes lists returned from the service.
Notably, I can choose between System.Array, System.Collections.ArrayList and System.Collections.Generic.List

using System.Linq;
var yourList = SomeDAO.GetRandomThings();
yourList.ToList().Sort( (thing, randomThing) => thing.CompareThisProperty.CompareTo( randomThing.CompareThisProperty ) );
That's pretty !ghetto.

Found a good post on this and thought I'd share. Check it out HERE
Basically.
You can create the following class and IComparer Classes
public class Widget {
public string Name = string.Empty;
public int Size = 0;
public Widget(string name, int size) {
this.Name = name;
this.Size = size;
}
}
public class WidgetNameSorter : IComparer<Widget> {
public int Compare(Widget x, Widget y) {
return x.Name.CompareTo(y.Name);
}
}
public class WidgetSizeSorter : IComparer<Widget> {
public int Compare(Widget x, Widget y) {
return x.Size.CompareTo(y.Size);
}
}
Then If you have an IList, you can sort it like this.
List<Widget> widgets = new List<Widget>();
widgets.Add(new Widget("Zeta", 6));
widgets.Add(new Widget("Beta", 3));
widgets.Add(new Widget("Alpha", 9));
widgets.Sort(new WidgetNameSorter());
widgets.Sort(new WidgetSizeSorter());
But Checkout this site for more information... Check it out HERE

Is this a valid solution?
IList<string> ilist = new List<string>();
ilist.Add("B");
ilist.Add("A");
ilist.Add("C");
Console.WriteLine("IList");
foreach (string val in ilist)
Console.WriteLine(val);
Console.WriteLine();
List<string> list = (List<string>)ilist;
list.Sort();
Console.WriteLine("List");
foreach (string val in list)
Console.WriteLine(val);
Console.WriteLine();
list = null;
Console.WriteLine("IList again");
foreach (string val in ilist)
Console.WriteLine(val);
Console.WriteLine();
The result was:
IList
B
A
C
List
A
B
C
IList again
A
B
C

This looks MUCH MORE SIMPLE if you ask me. This works PERFECTLY for me.
You could use Cast() to change it to IList then use OrderBy():
var ordered = theIList.Cast<T>().OrderBy(e => e);
WHERE T is the type eg. Model.Employee or Plugin.ContactService.Shared.Contact
Then you can use a for loop and its DONE.
ObservableCollection<Plugin.ContactService.Shared.Contact> ContactItems= new ObservableCollection<Contact>();
foreach (var item in ordered)
{
ContactItems.Add(item);
}

Convert your IList into List<T> or some other generic collection and then you can easily query/sort it using System.Linq namespace (it will supply bunch of extension methods)

Related

How to use IComparable to sort a dictionary of Class Objects

So I am trying to implement a sort on a dictionary to sort alphabetically by name. My class inherits IComparable and contains a compareTo(Object alpha)
method in the class. My problem is trying to implement this onto my dictionary and sort in that way.
I am reading from all names from a file and placing into a dictionary
I basically just want to know how to use this method since I could just extract name from the dictionary and sort then plug back in and get the other data I need. If anyone can help that would be great.
Here is the CompareTo method:
public int CompareTo(Object alpha)
{
if (alpha == null) throw new ArgumentNullException();
Subreddit rightOp = alpha as Subreddit;
if (rightOp != null)
return name.CompareTo(rightOp.name);
else
throw new ArgumentException("[Subreddit]:CompareTo argument is
not a Subreddit");
}
You can not use Dictionary<TKey,TValue> with IComparer<T> you should use SortedDictionary<TKey,TValue> instead. See https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.sorteddictionary-2?view=netframework-4.8 for details and examples
The new SortedDictionary<TKey,TValue>() will use Comparer<T>.Default and if type TKey implements the System.IComparable<T> generic interface, the default comparer uses that implementation. or you pass a comparer to the constructor. Here is an example
using System;
using System.Collections.Generic;
namespace ConsoleTestApp
{
class Program
{
static void Main(string[] args)
{
var sortedDictionary = new SortedDictionary<Subreddit, Payload>(new KeyComparer());
sortedDictionary.Add(new Subreddit {Name = "B"}, new Payload());
sortedDictionary.Add(new Subreddit {Name = "A"}, new Payload());
sortedDictionary.Add(new Subreddit {Name = "C"}, new Payload());
foreach (var keyValuePair in sortedDictionary)
{
Console.WriteLine($"{keyValuePair.Key.Name}");
}
Console.WriteLine("Press any key to exit program.");
Console.ReadKey();
}
}
public class Subreddit
{
public string Name { get; set; }
}
public class Payload
{
public string Data1 { get; set; }
public int Data2 { get; set; }
}
public class KeyComparer : IComparer<Subreddit>
{
public int Compare(Subreddit x, Subreddit y)
{
if (x?.Name == null)
throw new ArgumentException("[Subreddit]:CompareTo argument is not a Subreddit", nameof(x));
if (y?.Name == null)
throw new ArgumentException("[Subreddit]:CompareTo argument is not a Subreddit", nameof(y));
return string.Compare(x.Name, y.Name, StringComparison.Ordinal);
}
}
}
/*
The Output will be:
A
B
C
*/
If the key is a string only you do not need the class Subreddit with only one string property. You could simplify it to this and use the default implementation to sort strings.
using System;
using System.Collections.Generic;
namespace ConsoleTestApp
{
class Program
{
static void Main(string[] args)
{
var sortedDictionary = new SortedDictionary<string, Payload>();
sortedDictionary.Add("B", new Payload());
sortedDictionary.Add("A", new Payload());
sortedDictionary.Add("C", new Payload());
foreach (var keyValuePair in sortedDictionary)
{
Console.WriteLine($"{keyValuePair.Key}");
}
Console.WriteLine("Press any key to exit program.");
Console.ReadKey();
}
}
public class Payload
{
public string Data1 { get; set; }
public int Data2 { get; set; }
}
}
/*
The Output will be:
A
B
C
*/
Unlike List and Array Dictionary doesn't support sorting where you could implement IComparable interface and add your sort logic into CompareTo method.
But you can create your custom Comparer to use in OrderBy to somehow get the Dictionary items ordered as per your own requirement and return to a list of KeyValuePair. This is how you do this.
implement IComparer interface with given type, KeyValuePair TKey,TValue in your case, implement the Compare method with your comparison logic:
public class MyDictionaryComparer : IComparer<KeyValuePair<Subreddit, int>>
{
public int Compare(KeyValuePair<Subreddit, int> lhs, KeyValuePair<Subreddit, int> rhs)
{
return lhs.Key.name.CompareTo(rhs.Key.name);
}
}
Use:
Dictionary<Subreddit, int> data = new Dictionary<Subreddit, int>();
//Add some data
var sortedData = data.OrderBy(item => item, new MyDictionaryComparer());
Okay so what I ended up doing was creating an ArrayList of just Dicitonary.value.names
Then I call ArrayList.sort() which uses the IComparable interface and
my CompareTo(Object Alpha) to sort by name descending.
Once I had the sorted names in the array I used 2 foreach loops to compare the name values in the sorted ArrayList and the original dictionary with the other values I needed. Since I was checking the sorted ArrayList against the dictionary it automatically grabbed the data with the names in sorted Order.
From here I took all values associated with that name and threw it into another dictionary that was completely sorted. Now its probably not running at O(n) time but it works... Here's the code:
public void sortDictionaryByName()
{
//GOAL: Get all the values from the dictionary into a list that can use the
.sort method
ArrayList sortedNames = new ArrayList();
foreach (KeyValuePair<uint, Subreddit> value in subredditsDictionary)
{
sortedNames.Add(value.Value.name.ToString());
}
sortedNames.Sort();
foreach (var value in sortedNames)
{
foreach (KeyValuePair<uint, Subreddit> key in subredditsDictionary)
{
if (value.ToString() == key.Value.name.ToString())
{
Subreddit tempData = new Subreddit
{
subID = key.Key,
name = key.Value.name,
members = key.Value.members,
active = key.Value.active
};
sortedDictionary.Add(tempData.subID, tempData);
}
}
}
}

concrete implemantation of IEnumerable<T> that is not ICollection<T>

I would like to know if any of the classes in the .net framework that implement IEnumerable doesn't implement the ICollection interface.
I'm asking it because I can't get 100% code coverage in the following extension method that I wrote:
public static int GetSafeCount<T>(this IEnumerable<T> nullableCollaction)
{
if (nullableCollaction == null)
{
return 0;
}
var collection = nullableCollaction as ICollection<T>;
if (collection != null)
{
return collection.Count;
}
return nullableCollaction.Count();
}
The last line is not covered in any of my tests and I can't find the correct class to instantiate in order to cover it.
my test code is:
[Test]
public void GetSafeCount_NullObject_Return0()
{
IEnumerable<string> enumerable=null;
Assert.AreEqual(0, enumerable.GetSafeCount());
}
[Test]
public void GetSafeCount_NonICollectionObject_ReturnCount()
{
IEnumerable<string> enumerable = new string[]{};
Assert.AreEqual(0, enumerable.GetSafeCount());
}
Just use any LINQ operation, e.g. Where:
[Test]
public void GetSafeCount_NonICollectionObject_ReturnCount()
{
IEnumerable<string> enumerable = new string[0].Where(x => x.Length == 0);
Assert.AreEqual(0, enumerable.GetSafeCount());
}
However, you can simplify your implementation by just deferring to Enumerable.Count(), which I'd expect to be optimized every way you'd like it to be:
public static int GetSafeCount<T>(this IEnumerable<T> nullableCollection)
=> nullableCollection == null ? 0 : nullableCollection.Count();
Or:
public static int GetSafeCount<T>(this IEnumerable<T> nullableCollection)
=> nullableCollection?.Count() ?? 0;
(Both assume C# 6...)
At that point, it makes sense to only have two tests: one for a null argument, one for a non-null argument.
You can use the Stack<T> class, it implements ICollection and IEnumerable<T> but not ICollection<T>.
Here is how the class is defined:
public class Stack<T> : IEnumerable<T>, IEnumerable, ICollection,
IReadOnlyCollection<T>
He's an example of a IEnumerable<T> that is not a ICollection<T>:
public class MyClass : IEnumerable<int>
{
public List<int> ints = new List<int> { 1, 2, 3, 4, 5 };
public IEnumerator<int> GetEnumerator()
{
foreach (var i in ints)
{
yield return i;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return this as IEnumerator;
}
}
Now you can do this:
foreach(var item in new MyClass())
{
// do something
}
But can't do this, since it's not an ICollection
var coll = new MyClass() as ICollection<int>; // null!!!

C# Cast List of MyType to List of objects

I'm writing an application where I am required to use Reflection to call a method which has parameters of type MyObject.
Method (List<MyObject> input , out List<MyObject> output,..... );
Using reflection I send the parameter of type Object. How can I cast List<MyObject> to List<object>
var parameters = new Object[] { inputs, outputs, userPrams };
System.Type classType = typeof(MyClass);
object instance = Activator.CreateInstance(classType);
classType.InvokeMember(name, BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public,null, instance, parameters);
In the code above both input and output are lists of type MyObject
I tried to Cast them to List of Objects but this doesn't work
x.Outputs = grOutputs as IList<object>
Can anyone help?
Your question is not 100% clear, so I assumed the problem you're facing is the one you put in the title:
Cast List of MyType to List of objects
As #Charles said, IList<T> and List<T> are not variant, so you can't cast IList<DerivedClass> to IList<BaseClass>. You have to create new List<BaseClass>.
There are many ways to do that, I think there are two you should consider:
You can use Cast and ToList, but it will require using System.Linq.
var listOfStrings = new List<string>() { "foo", "bar" };
var listOfObjects = listOfStrings.Cast<object>().ToList();
To avoid that, you can use new List<T>(IEnumerable<T> source) constructor. Because IEnumerable<T> is covariant, you can do following:
var listOfStrings = new List<string>() { "foo", "bar" };
var listOfObjects = new List<object>(listOfString);
You might well want to do something like this:
var dogs = new List<Dog>();
var pets = (List<object>)dogs;
pets.Add(new Cat());
The C# language is heavily invested in you stop mixing cats and dogs like this. It violates the hard guarantee that the list only ever contains dogs. You'll have to do it like this instead:
var dogs = new List<Dog>();
var pets = new List<object>(dogs);
pets.Add(new Cat());
Which is fine, it creates a new list, one that no longer guarantees that it only ever contains dogs since it only promises that the list contains object. Pretty useless, typically, you basically lose all knowledge of what the list contains. Forcing you to write hunt-the-fox code that uses the as operator or Reflection to find the proper animal back. Code that fails to do its job at run-time instead of the compiler telling you that its wrong code at build time, when you're still in the comfortable cubicle cocoon.
Which it did.
IList<T> is not covariant, you would need to create a new list if you wanted IList<object>:
x.Outputs = grOutputs.Cast<object>().ToList();
If I understand your question, you could try something like this :
var objList = myClassList.OfType<object>();
You cannot make your desired cast because, as others have written, collections in c# are not covariant.
You can either create a new list, or introduce a ListWrapper class like so:
public class ListWrapper<TOut, TIn> : IList<TOut> where TIn : class, TOut where TOut : class
{
readonly IList<TIn> list;
public ListWrapper(IList<TIn> list)
{
if (list == null)
throw new NullReferenceException();
this.list = list;
}
#region IList<TOut> Members
public int IndexOf(TOut item)
{
TIn itemIn = item as TIn;
if (itemIn != item)
return -1;
return list.IndexOf(itemIn);
}
public void Insert(int index, TOut item)
{
list.Insert(index, (TIn)item);
}
public void RemoveAt(int index)
{
list.RemoveAt(index);
}
public TOut this[int index]
{
get
{
return list[index];
}
set
{
list[index] = (TIn)value;
}
}
#endregion
#region ICollection<TOut> Members
public void Add(TOut item)
{
list.Add((TIn)item);
}
public void Clear()
{
list.Clear();
}
public bool Contains(TOut item)
{
TIn itemIn = item as TIn;
if (itemIn != item)
return false;
return list.Contains(itemIn);
}
public void CopyTo(TOut[] array, int arrayIndex)
{
foreach (var item in list)
{
array[arrayIndex] = item;
arrayIndex++;
}
}
public int Count
{
get { return list.Count; }
}
public bool IsReadOnly
{
get
{
return list.IsReadOnly;
}
}
public bool Remove(TOut item)
{
return list.Remove(item as TIn);
}
#endregion
#region IEnumerable<TOut> Members
public IEnumerator<TOut> GetEnumerator()
{
foreach (var item in list)
yield return item;
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
You might want to make the wrapper read-only since the setter could throw an exception if the incoming object is not of the inner list's item type.

How should I use properties when dealing with read-only List<T> members

When I want to make a value type read-only outside of my class I do this:
public class myClassInt
{
private int m_i;
public int i {
get { return m_i; }
}
public myClassInt(int i)
{
m_i = i;
}
}
What can I do to make a List<T> type readonly (so they can't add/remove elements to/from it) outside of my class? Now I just declare it public:
public class myClassList
{
public List<int> li;
public myClassList()
{
li = new List<int>();
li.Add(1);
li.Add(2);
li.Add(3);
}
}
You can expose it AsReadOnly. That is, return a read-only IList<T> wrapper. For example ...
public ReadOnlyCollection<int> List
{
get { return _lst.AsReadOnly(); }
}
Just returning an IEnumerable<T> is not sufficient. For example ...
void Main()
{
var el = new ExposeList();
var lst = el.ListEnumerator;
var oops = (IList<int>)lst;
oops.Add( 4 ); // mutates list
var rol = el.ReadOnly;
var oops2 = (IList<int>)rol;
oops2.Add( 5 ); // raises exception
}
class ExposeList
{
private List<int> _lst = new List<int>() { 1, 2, 3 };
public IEnumerable<int> ListEnumerator
{
get { return _lst; }
}
public ReadOnlyCollection<int> ReadOnly
{
get { return _lst.AsReadOnly(); }
}
}
Steve's answer also has a clever way to avoid the cast.
There is limited value in attempting to hide information to such an extent. The type of the property should tell users what they're allowed to do with it. If a user decides they want to abuse your API, they will find a way. Blocking them from casting doesn't stop them:
public static class Circumventions
{
public static IList<T> AsWritable<T>(this IEnumerable<T> source)
{
return source.GetType()
.GetFields(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance)
.Select(f => f.GetValue(source))
.OfType<IList<T>>()
.First();
}
}
With that one method, we can circumvent the three answers given on this question so far:
List<int> a = new List<int> {1, 2, 3, 4, 5};
IList<int> b = a.AsReadOnly(); // block modification...
IList<int> c = b.AsWritable(); // ... but unblock it again
c.Add(6);
Debug.Assert(a.Count == 6); // we've modified the original
IEnumerable<int> d = a.Select(x => x); // okay, try this...
IList<int> e = d.AsWritable(); // no, can still get round it
e.Add(7);
Debug.Assert(a.Count == 7); // modified original again
Also:
public static class AlexeyR
{
public static IEnumerable<T> AsReallyReadOnly<T>(this IEnumerable<T> source)
{
foreach (T t in source) yield return t;
}
}
IEnumerable<int> f = a.AsReallyReadOnly(); // really?
IList<int> g = f.AsWritable(); // apparently not!
g.Add(8);
Debug.Assert(a.Count == 8); // modified original again
To reiterate... this kind of "arms race" can go on for as long as you like!
The only way to stop this is to completely break the link with the source list, which means you have to make a complete copy of the original list. This is what the BCL does when it returns arrays. The downside of this is that you are imposing a potentially large cost on 99.9% of your users every time they want readonly access to some data, because you are worried about the hackery of 00.1% of users.
Or you could just refuse to support uses of your API that circumvent the static type system.
If you want a property to return a read-only list with random access, return something that implements:
public interface IReadOnlyList<T> : IEnumerable<T>
{
int Count { get; }
T this[int index] { get; }
}
If (as is much more common) it only needs to be enumerable sequentially, just return IEnumerable:
public class MyClassList
{
private List<int> li = new List<int> { 1, 2, 3 };
public IEnumerable<int> MyList
{
get { return li; }
}
}
UPDATE Since I wrote this answer, C# 4.0 came out, so the above IReadOnlyList interface can take advantage of covariance:
public interface IReadOnlyList<out T>
And now .NET 4.5 has arrived and it has... guess what...
IReadOnlyList interface
So if you want to create a self-documenting API with a property that holds a read-only list, the answer is in the framework.
JP's answer regarding returning IEnumerable<int> is correct (you can down-cast to a list), but here is a technique that prevents the down-cast.
class ExposeList
{
private List<int> _lst = new List<int>() { 1, 2, 3 };
public IEnumerable<int> ListEnumerator
{
get { return _lst.Select(x => x); } // Identity transformation.
}
public ReadOnlyCollection<int> ReadOnly
{
get { return _lst.AsReadOnly(); }
}
}
The identity transformation during enumeration effectively creates a compiler-generated iterator - a new type which is not related to _lst in any way.
Eric Lippert has a series of articles on Immutability In C# on his blog.
The first article in the series can be found here.
You might also find useful Jon Skeet's answer to a similar question.
public List<int> li;
Don't declare public fields, it's generally considered bad practice... wrap it in a property instead.
You can expose your collection as a ReadOnlyCollection :
private List<int> li;
public ReadOnlyCollection<int> List
{
get { return li.AsReadOnly(); }
}
public class MyClassList
{
private List<int> _lst = new List<int>() { 1, 2, 3 };
public IEnumerable<int> ListEnumerator
{
get { return _lst.AsReadOnly(); }
}
}
To check it
MyClassList myClassList = new MyClassList();
var lst= (IList<int>)myClassList.ListEnumerator ;
lst.Add(4); //At this point ypu will get exception Collection is read-only.
public static IEnumerable<T> AsReallyReadOnly<T>(this IEnumerable<T> source)
{
foreach (T t in source) yield return t;
}
if I add to Earwicker's example
...
IEnumerable<int> f = a.AsReallyReadOnly();
IList<int> g = f.AsWritable(); // finally can't get around it
g.Add(8);
Debug.Assert(a.Count == 78);
I get InvalidOperationException: Sequence contains no matching element.

foreach with index [duplicate]

This question already has answers here:
How do you get the index of the current iteration of a foreach loop?
(35 answers)
Closed 9 years ago.
Is there a C# equivalent of Python's enumerate() and Ruby's each_with_index?
I keep this extension method around for this:
public static void Each<T>(this IEnumerable<T> ie, Action<T, int> action)
{
var i = 0;
foreach (var e in ie) action(e, i++);
}
And use it like so:
var strings = new List<string>();
strings.Each((str, n) =>
{
// hooray
});
Or to allow for break-like behaviour:
public static bool Each<T>(this IEnumerable<T> ie, Func<T, int, bool> action)
{
int i = 0;
foreach (T e in ie) if (!action(e, i++)) return false;
return true;
}
var strings = new List<string>() { "a", "b", "c" };
bool iteratedAll = strings.Each ((str, n)) =>
{
if (str == "b") return false;
return true;
});
You can do the following
foreach (var it in someCollection.Select((x, i) => new { Value = x, Index = i }) )
{
if (it.Index > SomeNumber) //
}
This will create an anonymous type value for every entry in the collection. It will have two properties
Value: with the original value in the collection
Index: with the index within the collection
The C# foreach doesn't have a built in index. You'll need to add an integer outside the foreach loop and increment it each time.
int i = -1;
foreach (Widget w in widgets)
{
i++;
// do something
}
Alternatively, you could use a standard for loop as follows:
for (int i = 0; i < widgets.Length; i++)
{
w = widgets[i];
// do something
}
I like being able to use foreach, so I made an extension method and a structure:
public struct EnumeratedInstance<T>
{
public long cnt;
public T item;
}
public static IEnumerable<EnumeratedInstance<T>> Enumerate<T>(this IEnumerable<T> collection)
{
long counter = 0;
foreach (var item in collection)
{
yield return new EnumeratedInstance<T>
{
cnt = counter,
item = item
};
counter++;
}
}
and an example use:
foreach (var ii in new string[] { "a", "b", "c" }.Enumerate())
{
Console.WriteLine(ii.item + ii.cnt);
}
One nice thing is that if you are used to the Python syntax, you can still use it:
foreach (var ii in Enumerate(new string[] { "a", "b", "c" }))
Aside from the LINQ answers already given, I have a "SmartEnumerable" class which allows you to get the index and the "first/last"-ness. It's a bit ugly in terms of syntax, but you may find it useful.
We can probably improve the type inference using a static method in a nongeneric type, and implicit typing will help too.
My solution involves a simple Pair class I created for general utility, and which is operationally essentially the same as the framework class KeyValuePair. Then I created a couple extension functions for IEnumerable called Ordinate (from the set theory term "ordinal").
These functions will return for each item a Pair object containing the index, and the item itself.
public static IEnumerable<Pair<Int32, X>> Ordinate<X>(this IEnumerable<X> lhs)
{
return lhs.Ordinate(0);
}
public static IEnumerable<Pair<Int32, X>> Ordinate<X>(this IEnumerable<X> lhs, Int32 initial)
{
Int32 index = initial - 1;
return lhs.Select(x => new Pair<Int32, X>(++index, x));
}
No, there is not.
As other people have shown, there are ways to simulate Ruby's behavior. But it is possible to have a type that implements IEnumerable that does not expose an index.
This is your collection
var values = new[] {6, 2, 8, 45, 9, 3, 0};
Make a range of indexes for this collection
var indexes = Enumerable.Range(0, values.Length).ToList();
Use the range to iterate with index
indexes.ForEach(i => values[i] += i);
indexes.ForEach(i => Console.Write("[{0}] = {1}", i, values[i]));
I just figured out interesting solution:
public class DepthAware<T> : IEnumerable<T>
{
private readonly IEnumerable<T> source;
public DepthAware(IEnumerable<T> source)
{
this.source = source;
this.Depth = 0;
}
public int Depth { get; private set; }
private IEnumerable<T> GetItems()
{
foreach (var item in source)
{
yield return item;
++this.Depth;
}
}
public IEnumerator<T> GetEnumerator()
{
return GetItems().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
// Generic type leverage and extension invoking
public static class DepthAware
{
public static DepthAware<T> AsDepthAware<T>(this IEnumerable<T> source)
{
return new DepthAware<T>(source);
}
public static DepthAware<T> New<T>(IEnumerable<T> source)
{
return new DepthAware<T>(source);
}
}
Usage:
var chars = new[] {'a', 'b', 'c', 'd', 'e', 'f', 'g'}.AsDepthAware();
foreach (var item in chars)
{
Console.WriteLine("Char: {0}, depth: {1}", item, chars.Depth);
}
It depends on the class you are using.
Dictionary<(Of <(TKey, TValue>)>) Class For Example Support This
The Dictionary<(Of <(TKey, TValue>)>) generic class provides a mapping from a set of keys to a set of values.
For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair<(Of <(TKey, TValue>)>) structure representing a value and its key. The order in which the items are returned is undefined.
foreach (KeyValuePair kvp in myDictionary) {...}

Categories

Resources