I would like to be able to do something like this for setting up a
mesh data structure.
IReadOnlyList<Point> points;
IReadOnlyList<IReadOnlyList<int>> triangles;
where the triangles are indices into the points list. Given an index
of a triangle ''ti'' we can find the points easily
IEnumerable<Point> points = triangles[ti].Select(pi=>points[pi])
However I would like to be able to define a convienience structure
IReadOnlyList<IReadOnlyList<Point>> trianglesAsPoints;
so I can do
IEnumerable<Point> points = triangles[ti]
The obvious way to do this would be to create a linq like selector
IReadOnlyList<T> Select( this IReadOnlyList<U> This
, Func<U,T> selector)
which returns an instance whose class overrides the following method and
invokes the selector
public interface IReadOnlyList<out T> : IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
{
// Summary:
// Gets the element at the specified index in the read-only list.
//
// Parameters:
// index:
// The zero-based index of the element to get.
//
// Returns:
// The element at the specified index in the read-only list.
T this[int index] { get; }
}
Does such a factory exist anywhere in the standard libs or nuget for this pattern?
Note I do not want IEnumerable as a result because I would lose the indexing ability
and the Count property, I just want to lazily transform the value which means not
copying all the values to a new list instance up front.
I don't believe there's anything which does this in the framework, no. It's obviously reasonably easy to implement yourself, but I believe you'll have to do it. It's entirely possible that there are 3rd party libraries which do it, but as IReadOnlyCollection was only in .NET 4.5 it's less likely than if the interface had existed for a while.
I'd suggest calling it something other than Select though - I'd use ProjectView or something similar. Of course that means it wouldn't work with LINQ query expressions, but it will be clearer to anyone reading the code that it's not just Enumerable.Select.
Here is a hand rolled solution to the problem
public static class CollectionMixins
{
private class ReadOnlyListProjection<U,T> : IReadOnlyList<T>
{
public Func<U,T> Selector { get; private set; }
public IList<U> List { get; private set; }
public ReadOnlyListProjection(IList<U> list, Func<U, T> selector)
{
List = list;
Selector = selector;
}
public T this[int index]
{
get { return Selector(List[index]); }
}
public int Count
{
get { return List.Count; }
}
public IEnumerator<T> GetEnumerator()
{
return List.Select(Selector).GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return List.Select(Selector).GetEnumerator();
}
}
public static IReadOnlyList<T> ProjectReadOnly<U, T>(this IList<U> This, Func<U, T> fn)
{
return new ReadOnlyListProjection<U, T>(This, fn);
}
}
so I can now do
IList<int> foo = new List<int>{0,1,2};
IReadOnlyList<string> bar = foo.ProjectReadOnly( x=>x.ToString() );
Related
I have the following code:
public interface ISomeObject
{
IList<ISomeObject> Objects { get; }
}
public class SomeObject : ISomeObject
{
public SomeObject()
{
Objects = new List<SomeObject>();
}
public List<SomeObject> Objects
{
get;
set;
}
IList<ISomeObject> ISomeObject.Objects
{
get
{
// What to do here?
// return Objects; // This doesn't work
return Objects.Cast<ISomeObject>().ToList(); // Works, but creates a copy each time.
}
}
SomeObject has a public property Objects that returns a List of class type. Clients knowing that class type can use that to do whatever they want. Clients only knowing about ISomeObject can use the Objects property only to get an IList<ISomeObject>. Because it is not allowed to cast List<SomeObject> to IList<ISomeObject> (due to the apple and banana issue) I need a way of converting that. The default way, using a Cast.ToList() works, but has the downside that it creates a new List each time the property is evaluated, which may be expensive. Changing ISomeObject.Objects to return an IEnumerable<ISomeObject> has the other downside that the client can't use indexing any more (which is quite relevant in my use case). And using Linq's ElementAt() call repeatedly is expensive, when used on an IEnumerable.
Has anybody got an idea on how to avoid either problem?
(of course, making SomeObject known everywhere is not an option).
You could/should implement a class similar to ReadOnlyCollection<T> to act as a proxy. Considering that it would be read only, it could be "covariant" (not language-side, but logically, meaning that it could proxy a TDest that is a subclass/interface of TSource) and then throw NotSupportedException() for all the write methods.
Something like this (code untested):
public class CovariantReadOlyList<TSource, TDest> : IList<TDest>, IReadOnlyList<TDest> where TSource : class, TDest
{
private readonly IList<TSource> source;
public CovariantReadOlyList(IList<TSource> source)
{
this.source = source;
}
public TDest this[int index] { get => source[index]; set => throw new NotSupportedException(); }
public int Count => source.Count;
public bool IsReadOnly => true;
public void Add(TDest item) => throw new NotSupportedException();
public void Clear() => throw new NotSupportedException();
public bool Contains(TDest item) => IndexOf(item) != -1;
public void CopyTo(TDest[] array, int arrayIndex)
{
// Using the nuget package System.Runtime.CompilerServices.Unsafe
// source.CopyTo(Unsafe.As<TSource[]>(array), arrayIndex);
// We love to play with fire :-)
foreach (TSource ele in source)
{
array[arrayIndex] = ele;
arrayIndex++;
}
}
public IEnumerator<TDest> GetEnumerator() => ((IEnumerable<TDest>)source).GetEnumerator();
public int IndexOf(TDest item)
{
TSource item2 = item as TSource;
if (ReferenceEquals(item2, null) && !ReferenceEquals(item, null))
{
return -1;
}
return source.IndexOf(item2);
}
public void Insert(int index, TDest item)
{
throw new NotSupportedException();
}
public bool Remove(TDest item)
{
throw new NotSupportedException();
}
public void RemoveAt(int index)
{
throw new NotSupportedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Use it like:
IList<string> strs = new List<string>();
IList<object> objs = new CovariantReadOlyList<string, object>(strs);
Changing ISomeObject.Objects to return an IEnumerable<ISomeObject> has the other downside that the client can't use indexing any more (which is quite relevant in my use case).
Indexing isn't just supported by the IList<T> interface, it's also supported by the IReadOnlyList<T> interface. Because IReadOnlyList<T> doesn't allow modification, it can be (and is) covariant just like IEnumerable<T> is.
So, just change the return type to IReadOnlyList<ISomeObject> and return the original list.
Of course, nothing prevents the caller from casting the result to List<SomeObject>, but the caller is supposed to have full access to that list anyway, so there is no security risk.
You may want try to encapsulate your List<SomeObject> making it an implementation detail and return IReadOnlyList<SomeObject> instead. Then SomeObject to ISomeObject cast want be unnecessary in interface implementation as well due to IReadOnlyList variance — you'll be able to return your Objects as IReadOnlyList<ISomeObject> .
Then just add some operations to mutate your underlying list like Add or Remove to container type if those are required.
Also I should mention that interfaces are not so good for restriction — evil consumer can easily cast your ISomeObject to SomeObject and do everything he wants, probably, you should reconsider your design. You'd better stick to such things as immutability and encapsulation for providing usable api. Explicitly use mutable builders then for immutable classes where it's reasonable.
Is there something inherently wrong with replacing
IDictionary<int, IEnumerable<string>>
with
ILookup<int, string>
I much prefer ILookup over IDictionary because of its more 'honest' interface and immutability.
However, I discovered that ILookup is unable to hold empty collections, so keys containing empty collections are simply do not exist in it. This is problem, because I also would like ILookup to convey information about all possible keys (even though some of them might be empty), so I can go like this:
var statistics = from grouping in myLookup
select new {grouping.Key, grouping.Count()};
which works with dictionary of enumerables, but unfortunately does not work with ILookup. It is just impossible to have entries where grouping.Count()==0, as with IDictionary.
As John Skeet states,
There’s one other important difference between a lookup and a dictionary: if you ask a lookup for the sequence corresponding to a key which it doesn’t know about, it will return an empty sequence, rather than throwing an exception. (A key which the lookup does know about will never yield an empty sequence.)
Now, what is wrong if ILookup allowed empty groupings? In order to have the best of both worlds I am about to add Filter() extension method for ILookup that does just this, but need to resolve a problem that Linq does not allow to create empty IGroupings (so I have to implement my own class), but I feel that maybe I am doing something against design principles of Linq.
Example
Two options:
1) you could create a nice, straightforward singleton-esque EmptyLookup class as follows:
var empty = EmptyLookup<int, string>.Instance;
// ...
public static class EmptyLookup<TKey, TElement>
{
private static readonly ILookup<TKey, TElement> _instance
= Enumerable.Empty<TElement>().ToLookup(x => default(TKey));
public static ILookup<TKey, TElement> Instance
{
get { return _instance; }
}
}
2) You can create a singleton class for empty lookups.
public sealed class EmptyLookup<T, K> : ILookup<T, K>
{
private static readonly EmptyLookup<T, K> _instance
= new EmptyLookup<T, K>();
public static EmptyLookup<T, K> Instance
{
get { return _instance; }
}
private EmptyLookup() { }
public bool Contains(T key)
{
return false;
}
public int Count
{
get { return 0; }
}
public IEnumerable<K> this[T key]
{
get { return Enumerable.Empty<K>(); }
}
public IEnumerator<IGrouping<T, K>> GetEnumerator()
{
yield break;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
yield break;
}
}
then you can write code like this:
var x = EmptyLookup<int, int>.Instance;
/*The benefit of creating a new class is that you can use the "is" operator and check for type equality:*/
if (x is EmptyLookup<,>) {
// ....
}
There is no wrong in keeping empty groupings is lookup, it's just that lookup does not support it because of it's nature in Linq.
You have to create an extension method by yourself.
This code is not compiling, and it's throwing the following error:
The type 'TestesInterfaces.MyCollection' already contains a definition for 'Current'
But when I delete the ambiguous method, it keeps giving other errors.
Can anyone help?
public class MyCollection<T> : IEnumerator<T>
{
private T[] vector = new T[1000];
private int actualIndex;
public void Add(T elemento)
{
this.vector[vector.Length] = elemento;
}
public bool MoveNext()
{
actualIndex++;
return (vector.Length > actualIndex);
}
public void Reset()
{
actualIndex = -1;
}
void IDisposable.Dispose() { }
public Object Current
{
get
{
return Current;
}
}
public T Current
{
get
{
try
{
T element = vector[actualIndex];
return element;
}
catch (IndexOutOfRangeException e)
{
throw new InvalidOperationException(e.Message);
}
}
}
}
I think you're misunderstanding IEnumerator<T>. Typically, collections implement IEnumerable<T>, not IEnumerator<T>. You can think of them like this:
When a class implements IEnumerable<T>, it is stating "I am a collection of things that can be enumerated."
When a class implements IEnumerator<T>, it is stating "I am a thing that enumerates over something."
It is rare (and probably wrong) for a collection to implement IEnumerator<T>. By doing so, you're limiting your collection to a single enumeration. If you try to loop through the collection within a segment of code that's already looping through the collection, or if you try to loop through the collection on multiple threads simultaneously, you won't be able to do it because your collection is itself storing the state of the enumeration operation. Typically, collections (implementing IEnumerable<T>) return a separate object (implementing IEnumerator<T>) and that separate object is responsible for storing the state of the enumeration operation. Therefore, you can have any number of concurrent or nested enumerations because each enumeration operation is represented by a distinct object.
Also, in order for the foreach statement to work, the object after the in keyword, must implement IEnumerable or IEnumerable<T>. It will not work if the object only implements IEnumerator or IEnumerator<T>.
I believe this is the code you're looking for:
public class MyCollection<T> : IEnumerable<T>
{
private T[] vector = new T[1000];
private int count;
public void Add(T elemento)
{
this.vector[count++] = elemento;
}
public IEnumerator<T> GetEnumerator()
{
return vector.Take(count).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
You need to define the interface the current is implementing.
Object IEnumerator.Current
{
//
}
public T Current
{
//
}
This way your class has 2 Current properties. but you can access them both.
MyCollection<string> col = new MyCollection<string>();
var ienumeratort = col.Current; //Uses IEnumerator<T>
var ienumerator = (IEnumerator)col.Current; //uses IEnumerator
I think with C# 2.0 onwards, you have a very easy way of implementing iterator and compiler does a lot of heavy lifting behind the scene by creating state machine. It's worth looking into it. Having said that, in that case your implementation would look something below:
public class MyCollection<T>
{
private T[] vector = new T[1000];
private int actualIndex;
public void Add(T elemento)
{
this.vector[vector.Length] = elemento;
}
public IEnumerable<T> CreateEnumerable()
{
for (int index = 0; index < vector.Length; index++)
{
yield return vector[(index + actualIndex)];
}
}
}
I am not sure about the purpose of actualIndex though - but i hope you get the idea.
After proper initialization of MyCollection, below is snippet somewhat looks like from consumer perspective:
MyCollection<int> mycoll = new MyCollection<int>();
foreach (var num in mycoll.CreateEnumerable())
{
Console.WriteLine(num);
}
I know how to implement the non generic IEnumerable, like this:
using System;
using System.Collections;
namespace ConsoleApplication33
{
class Program
{
static void Main(string[] args)
{
MyObjects myObjects = new MyObjects();
myObjects[0] = new MyObject() { Foo = "Hello", Bar = 1 };
myObjects[1] = new MyObject() { Foo = "World", Bar = 2 };
foreach (MyObject x in myObjects)
{
Console.WriteLine(x.Foo);
Console.WriteLine(x.Bar);
}
Console.ReadLine();
}
}
class MyObject
{
public string Foo { get; set; }
public int Bar { get; set; }
}
class MyObjects : IEnumerable
{
ArrayList mylist = new ArrayList();
public MyObject this[int index]
{
get { return (MyObject)mylist[index]; }
set { mylist.Insert(index, value); }
}
IEnumerator IEnumerable.GetEnumerator()
{
return mylist.GetEnumerator();
}
}
}
However I also notice that IEnumerable has a generic version, IEnumerable<T>, but I can't figure out how to implement it.
If I add using System.Collections.Generic; to my using directives, and then change:
class MyObjects : IEnumerable
to:
class MyObjects : IEnumerable<MyObject>
And then right click on IEnumerable<MyObject> and select Implement Interface => Implement Interface, Visual Studio helpfully adds the following block of code:
IEnumerator<MyObject> IEnumerable<MyObject>.GetEnumerator()
{
throw new NotImplementedException();
}
Returning the non generic IEnumerable object from the GetEnumerator(); method doesn't work this time, so what do I put here? The CLI now ignores the non generic implementation and heads straight for the generic version when it tries to enumerate through my array during the foreach loop.
If you choose to use a generic collection, such as List<MyObject> instead of ArrayList, you'll find that the List<MyObject> will provide both generic and non-generic enumerators that you can use.
using System.Collections;
class MyObjects : IEnumerable<MyObject>
{
List<MyObject> mylist = new List<MyObject>();
public MyObject this[int index]
{
get { return mylist[index]; }
set { mylist.Insert(index, value); }
}
public IEnumerator<MyObject> GetEnumerator()
{
return mylist.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
You probably do not want an explicit implementation of IEnumerable<T> (which is what you've shown).
The usual pattern is to use IEnumerable<T>'s GetEnumerator in the explicit implementation of IEnumerable:
class FooCollection : IEnumerable<Foo>, IEnumerable
{
SomeCollection<Foo> foos;
// Explicit for IEnumerable because weakly typed collections are Bad
System.Collections.IEnumerator IEnumerable.GetEnumerator()
{
// uses the strongly typed IEnumerable<T> implementation
return this.GetEnumerator();
}
// Normal implementation for IEnumerable<T>
IEnumerator<Foo> GetEnumerator()
{
foreach (Foo foo in this.foos)
{
yield return foo;
//nb: if SomeCollection is not strongly-typed use a cast:
// yield return (Foo)foo;
// Or better yet, switch to an internal collection which is
// strongly-typed. Such as List<T> or T[], your choice.
}
// or, as pointed out: return this.foos.GetEnumerator();
}
}
Why do you do it manually? yield return automates the entire process of handling iterators. (I also wrote about it on my blog, including a look at the compiler generated code).
If you really want to do it yourself, you have to return a generic enumerator too. You won't be able to use an ArrayList any more since that's non-generic. Change it to a List<MyObject> instead. That of course assumes that you only have objects of type MyObject (or derived types) in your collection.
If you work with generics, use List instead of ArrayList. The List has exactly the GetEnumerator method you need.
List<MyObject> myList = new List<MyObject>();
make mylist into a List<MyObject>, is one option
Note that the IEnumerable<T> allready implemented by the System.Collections so another approach is to derive your MyObjects class from System.Collections as a base class (documentation):
System.Collections: Provides the base class for a generic collection.
We can later make our own implemenation to override the virtual System.Collections methods to provide custom behavior (only for ClearItems, InsertItem, RemoveItem, and SetItem along with Equals, GetHashCode, and ToString from Object). Unlike the List<T> which is not designed to be easily extensible.
Example:
public class FooCollection : System.Collections<Foo>
{
//...
protected override void InsertItem(int index, Foo newItem)
{
base.InsertItem(index, newItem);
Console.Write("An item was successfully inserted to MyCollection!");
}
}
public static void Main()
{
FooCollection fooCollection = new FooCollection();
fooCollection.Add(new Foo()); //OUTPUT: An item was successfully inserted to FooCollection!
}
Please note that driving from collection recommended only in case when custom collection behavior is needed, which is rarely happens. see usage.
Does dot net have an interface like IEnumerable with a count property? I know about interfaces such as IList and ICollection which do offer a Count property but it seems like these interfaces were designed for mutable data structures first and use as a read only interface seems like an afterthought - the presence of an IsReadOnly field and mutators throwing exceptions when this property is true is IMO ample evidence for this.
For the time being I am using a custom interface called IReadOnlyCollection (see my own answer to this post) but I would be glad to know of other alternative approaches.
The key difference between the ICollection family and the IEnumerable family is the absence of certainty as to the count of items present (quite often the items will be generated/loaded/hydrated as needed) - in some cases, an Enumerable may not ever finish generating results, which is why the Count is missing.
Deriving and adding a Count is possible depending on your requirements, but it goes against this spirit, which is the purpose of ICollection - a collection of stuff that's all there.
Another way might be to use the System.Linq.Enumerable.Count method, i.e.
using System.Linq;
class X
{
void Y(IEnumerable<int> collection)
{
int itemCount = collection.Count();
}
}
or use the (System.Linq.Enumerable) .ToList() to pull all the items from the enumerator into a Collection and work from there.
(Also to answer your comment before having 50 rep:- the ".Count()" bit is a call to an extension method on the extension class System.Linq.Enumerable - the extension method is available on all things that derive from IEnumerable because the code has a "using System.Linq" which brings the extension methods in all classes in that namespace into scope - in this case its in the class Enumerable. If you're in VS, pressing F12 will bring you to the definition of S.L.Enumerable. BTW C# In Depth is a fantastic book for learning LINQ properly - its a page turner thats really helps you get the whole picture compared to learning the bits of LINQ piece by piece)
As of .Net 4.5, there are two new interfaces for this: IReadOnlyCollection<T> and IReadOnlyList<T>.
IReadOnlyCollection<T> is IEnumerable<T> with a Count property added, IReadOnlyList<T> also adds indexing.
It sounds like you really just want ReadOnlyCollection<T> - expose it as IList<T>, but by wrapping the original list like this you just get a read-only wrapper with an appropriate count.
Taking into consideration some of the comments I have decided to go with a wrapper class implementing a custom interface...
interface IReadOnlyCollection<T> : IEnumerable<T>
{
int Count { get; }
}
//This can now be not misused by downcasting to List
//The wrapper can also be used with lists since IList inherits from ICollection
public class CollectionWrapper<T> : IReadOnlyCollection<T>
{
public CollectionWrapper(ICollection<T> collection)
{
_collection = collection;
}
public int Count
{
get
{
return _collection.Count;
}
}
public IEnumerator<T> GetEnumerator()
{
return (IEnumerator<T>)_collection.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)((IEnumerable)_collection).GetEnumerator();
}
////////Private data///////
ICollection<T> _collection;
}
class Program
{
static void Main(string[] args)
{
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
CollectionWrapper<int> collection = new CollectionWrapper<int>(list);
Console.WriteLine("Count:{0}", collection.Count);
foreach (var x in collection)
{
Console.WriteLine(x);
}
foreach (var x in (IEnumerable)collection)
{
Console.WriteLine(x);
}
}
}
Thanks all for your suggestions.
Edit: Now cannot be misused by downcasting to List (or whatever).
IList can return IsReadOnly as true, which marks the collection as readonly. Other than that I'm afraid I don't know of anything fitting.
Since it's an interface, you would have to implement the Count property yourself, why don't you create a new interface that inherits IEnumerator and add a Count property?
IList or ICollection would be the way to go, if you want to use the standard interfaces.
Note that you can "hide" methods required by the interface if you don't want them in your class's public interface -- for example, since it's meaningless to add things to a readonly collection you can do this:
void ICollection<DataType>.Add(DataType item)
{
throw new NotSupportedException();
}
public DataType this[int index]
{
get { return InnerList[index]; }
}
DataType IList<DataType>.this[int index]
{
get { return this[index]; }
set { throw new NotSupportedException(); }
}
etc.
An array can be cast to an IList, which makes the IList ReadOnly == true :)
You can get .Count on IEnumerable with an extension method if you add a reference to System.Linq (in 3.5 anyway).
As Jon Skeet mentions, you're much better off using System.Collections.ObjectModel.ReadOnlyCollection instead of creating your own wrapper class.
Then you can implement your sample as follows:
class Program {
static void Main(string[] args) {
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
ReadOnlyCollection<int> collection = new ReadOnlyCollection<int>(list);
Console.WriteLine("Count:{0}", collection.Count);
foreach (var x in collection) {
Console.WriteLine(x);
}
foreach (var x in (IEnumerable)collection) {
Console.WriteLine(x);
}
}
}