I have this model of data:
public abstract class AbstractCollection
{
}
public abstract class TypedAbstractCollection<T1> : AbstractCollection
{
}
public class MyCollection<T> : TypedAbstractCollection<T>, IEnumerable<T>
{
private readonly List<T> _valueList = new List<T>();
public IEnumerator<T> GetEnumerator()
{
return _valueList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(T value)
{
_valueList.Add(value);
}
}
[XmlInclude(typeof(MyCollection<string>))]
public class Shallow : IEnumerable<AbstractCollection>
{
private readonly List<AbstractCollection> _listOfCollections = new List<AbstractCollection>();
public IEnumerator<AbstractCollection> GetEnumerator()
{
return _listOfCollections.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(AbstractCollection sample)
{
_listOfCollections.Add(sample);
}
}
I use IEnumerable in my collection with Add() function to automatically serialization it as collection, but when I try to serialization it in XML:
Shallow shallow = new Shallow
{
new MyCollection<string>
{
"first",
"second"
}
};
XmlSerializer formatter = new XmlSerializer(shallow.GetType(),
new[] { typeof(OneWayMapper<string, string>) });
using (FileStream fs = new FileStream("data.xml", FileMode.OpenOrCreate))
{
formatter.Serialize(fs, shallow);
}
I've got the strange error without any needed information:
The type 'MyCollection' may not be used in this context
But, if I will use instead of MyCollection class MyItem<T> with typed item value - there won't be any errors.
So it's ok with typed collections, abstract class and so on, but not with collection of collections.
How can I fix that?
And I found a problem. To make it work we have to make AbstractCollection inherit of IEnumerable.
And it's very understandable.
Related
I want to create a custom class that can be initialized like arrays can,
var myCollection = new MyCollection<string> {"a", "b", "c"}
Is there a syntax for creating a class that can interpret that?
I know how to do a similar thing with class properties, such as
var person = new Person { Name = "Santi", LastName = "Arizti" };
But that is not what I am looking for.
This question might already exist, but I just don't know the name of this feature to effectively search it online.
Your class must
Implement IEnumerable
Have an Add method
That's it.
public class MyCollection<T> : IEnumerable<T>
{
protected readonly List<T> _list = new List<T>();
public void Add(T item)
{
_list.Add(item);
}
IEnumerator IEnumerable.GetEnumerator()
{
return _list.GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return _list.GetEnumerator();
}
}
public class Program
{
public static void Main()
{
var x = new MyCollection<string>
{
"A","B"
};
}
}
Here is a Link to Fiddle
Constructing an object using {...} simply creates it using the default constructor and calls an Add method present on it for each of the arguments (or tuples of arguments if nested {...} is used). It only has to implement IEnumerable.
Your example is essentially equivalent to:
var myCollection = new MyCollection<string>();
myCollection.Add("a");
myCollection.Add("b");
myCollection.Add("c");
Here's the simplest example of such a class that can be "initialized" with anything:
public class TestClass : IEnumerable
{
public void Add<T>(params T[] args)
{
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
I had an idea about which I couldn't find any direct syntax. I was wondering if it was possible to overload a reference type so that when it is referenced in a certain way it redirects its reference type into a new one.
I'd like to show an example about this:
public class MyClass
{
public ICollection<int> CollectionProperty { get; private set; }
public MyClass()
{
this.CollectionProperty = new List<int>();
}
}
This is just a simple class, but when MyClass is referenced, for example in a foreach, I'd like it to reference its inner collection like this:
MyClass instance = new MyClass();
foreach(int item in instance)
{
// do stuff
}
So here an item would be an int value of the class's collection's.
It was just something I was curious about, I don't know if it's even possible, maybe with some kind of reference overloading, or I don't know.
Thank you for your answers!
You could implement IEnumerable in order to enable foreach functionality.
public class MyClass<T> : IEnumerable<T>
{
public List<T> Collection { get; set;}
public T this[int index]
{
get { return Collection[index]; }
set { Collection.Insert(index, value); }
}
public IEnumerator<T> GetEnumerator()
{
return Collection.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public MyClass()
{
Collection = new List<T>();
}
}
public class Program
{
public static void Main()
{
var instance = new MyClass<int>();
instance.Collection.Add(1);
instance.Collection.Add(2);
instance.Collection.Add(3);
foreach(int item in instance)
Console.WriteLine(item);
}
}
Output:
1 2 3
I'm creating a dictionary data structure which implements the IDictionary interface. I'm stuck when it comes to implementing the GetEnumerator method. I have an enumerator which gives KeyValuePair instances but from what I'm finding, I have to implement IDictionaryEnumerator.
Is there a simple way to transform a KeyValuePair enumerator to an IDictionaryEnumerator? I know I can do the following hack:
IDictionaryEnumerator GetEnumerator()
{
return new Dictionary(this.KeyValueEnumerator()).GetEnumerator();
}
But it seems very inefficient as it loads all the enumerator data.
Given that you told us that you have a KeyValueEnumerator() that returns a IEnumerator<KeyValuePair<,>>
// This you told us you have
public IEnumerator<KeyValuePair<TKey, TValue>> KeyValueEnumerator()
{
return something;
}
I built a MyDictionaryEnumerator that exposes a IDictionaryEnumerator interface
// This is what you need
public IDictionaryEnumerator GetEnumerator()
{
return new MyDictionaryEnumerator(KeyValueEnumerator());
}
public class MyDictionaryEnumerator : IDictionaryEnumerator
{
public MyDictionaryEnumerator(IEnumerator<KeyValuePair<TKey, TValue>> enumerator)
{
Enumerator = enumerator;
}
public IEnumerator<KeyValuePair<TKey, TValue>> Enumerator;
public DictionaryEntry Entry
{
get { return new DictionaryEntry(Enumerator.Current.Key, Enumerator.Current.Value); }
}
public object Key
{
get { return Enumerator.Current.Key; }
}
public object Value
{
get { return Enumerator.Current.Value; }
}
public object Current
{
get { return Entry; }
}
public bool MoveNext()
{
return Enumerator.MoveNext();
}
public void Reset()
{
Enumerator.Reset();
}
}
The MyDictionaryEnumerator is a very simple class that builds around the KeyValueEnumerator() you have returning DictionaryEntry objects and/or the Key and the Value (I'll say it's an implementation of the Adapter Pattern)
I wanted to make a read-only indexable "view" of a list, with the slight twist that the read only view should enumerate to an interface of the list type.
interface IIndexable<out T> : IEnumerable<T>
{
T this[int i] { get; }
int Count { get; }
}
The usage scenario would look something like this.
List<Dog> dogs = new List<Dog>[]{ dog1, dog2 }; // Dog implements IAnimal
IIndexable<IAnimal> animals = dogs.AsIIndexable<Dog, IAnimal>();
IAnimal first = animals[0];
I thought this would be possible given covariance and type constraints, but maybe I'm mistaken here.
My first attempt looks like this, which doesn't work because of the type of the enumerator.
internal class ListIndexable<TC, T> : IIndexable<T> where TC : T
{
private List<TC> list;
public ListIndexable(List<TC> list) { this.list = list; }
public T this[int i] { get { return list[i]; } }
public IEnumerator<T> GetEnumerator()
{
return list.GetEnumerator(); // Computer says no.
}
}
Why can't I return an IEnumerator<TC> as an IEnumerator<T>? The type is covariant and I have constrained it with TC : T. Would it really be unsafe to return an IEnumerator<TC>, or is it simply a weakness here that the compiler's reasoning ignores the type constraint?
I could solve it by using a custom enumerator that wraps the IEnumerator<TC> and returns its items as T's which is of course perfectly legal, but I'm just curious why the above solution can't work.
internal class ListIndexable<TC, T> : IIndexable<T> where TC : T
{
private List<TC> list;
public ListIndexable(List<TC> list) { this.list = list; }
public T this[int i] { get { return list[i]; } }
public IEnumerator<T> GetEnumerator()
{
return new Enumerator(list.GetEnumerator());
}
class Enumerator : IEnumerator<T>
{
private IEnumerator<TC> inner;
internal Enumerator(IEnumerator<TC> inner) { this.inner = inner; }
public bool MoveNext()
{
return inner.MoveNext();
}
public T Current
{
get { return inner.Current; }
}
// ...
}
}
Your original code does not work because of value types. You cannot do the following:
IEnumerable<int> ints = new[] { 1, 2 };
IEnumerable<object> os = ints;
so the compiler won't accept your definition since it can't guarantee that IEnumerable<TC> is compatible with IEnumerable<T> in general. If you add class constraints to T and TC it compiles:
internal class ListIndexable<TC, T> : IIndexable<T> where TC : class, T where T : class
{
}
However, you can define ListIndexable with only one type parameter instead of two. If you change your definition to:
internal class ListIndexable<T> : IIndexable<T>
{
private List<T> list;
public ListIndexable(List<T> list) { this.list = list; }
public T this[int i] { get { return list[i]; } }
public IEnumerator<T> GetEnumerator()
{
return list.GetEnumerator();
}
}
then you can do:
IIndexable<IAnimal> animals = dogs.AsIIndexable();
where AsIndexable can be defined simply as:
public static ListIndexable<T> AsIndexable<T>(this List<T> list)
{
return new ListIndexable<T>(list);
}
If all you need is to create a read-only collection, you can use ReadOnlyCollection to wrap your list, eg:
var dogs = new List<Dog> {new Dog{Name="A"}, new Dog{Name="B"}, new Dog{Name="C"}};
var ro=new ReadOnlyCollection<Dog>(dogs);
IEnumerable<IAnimal> a = ro;
Here is my problem: there is a class that contains a inner collection (or list, or array, or something like this) of some some class and It must expose a public read-only collection of items, which are properties (or fields) of relative items in inner collection. For example:
//Inner collection consists of items of this class
class SomeClass
{
public int _age;
//This property is needed for exposing
public string Age { get { return this._age.ToString(); } }
}
//Keeps inner collection and expose outer read-only collection
class AnotherClass
{
private List<SomeClass> _innerList = new List<SomeClass> ();
public ReadOnlyCollection<string> Ages
{
get
{
//How to implement what i need?
}
}
}
I know a simple way to do this by the use of a pair of inner lists, where the second keeps values of needed properties of first. Something like this:
//Inner collection consists of items of this class
class SomeClass
{
public int _age;
//This property is needed for exposing
public string Age { get { return this._age.ToString(); } }
}
//Keeps inner collection and expose outer read-only collection
class AnotherClass
{
private List<SomeClass> _innerList = new List<SomeClass> ();
private List<string> _innerAgesList = new List<string> ();
public ReadOnlyCollection<string> Ages
{
get
{
return this._innerAgesList.AsreadOnly();
}
}
}
But I dislike this overhead. May be there is some way to do what I want with exposing interfaces. Help me, please!
Hurra!
It seems that the best solution has been found. Due to the post of Groo
this problem found its almost universal answer. Here is It (we need to add two entity):
public interface IIndexable<T> : IEnumerable<T>
{
T this[int index] { get; }
int Count { get; }
}
class Indexer <Tsource, Ttarget> : IIndexable<Ttarget>
{
private IList<Tsource> _source = null;
private Func<Tsource, Ttarget> _func = null;
public Indexer(IList<Tsource> list, Func<Tsource, Ttarget> projection)
{
this._source = list;
this._func = projection;
}
public Ttarget this[int index] { get { return this._func(this._source[index]); } }
public int Count { get { return _source.Count; } }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
public IEnumerator<Ttarget> GetEnumerator()
{ foreach (Tsource src in this._source) yield return this._func(src); }
}
With them, our implementation looks like this:
//Inner collection consists of items of this class
class SomeClass
{
public int _age;
//This property is needed for exposing
public string Age { get { return this._age.ToString(); } }
}
//Keeps inner collection and expose outer read-only collection
class AnotherClass
{
private List<SomeClass> _innerList = new List<SomeClass> ();
private Indexer<SomeClass, string> _indexer = null;
public AnotherClass ()
{ this._indexer = new Indexer<SomeClass, string > (this._innerList, s => s.Age); }
public IIndexable<string> Ages { get { return this._indexer; } }
}
Thank Groo and the rest who answered. Hope, this helps someone else.
The overhead is not so significant if you consider that ReadOnlyCollection is a wrapper around the list (i.e. it doesn't create a copy of all the items).
In other words, if your class looked like this:
class AnotherClass
{
private ReadOnlyCollection<string> _readonlyList;
public ReadOnlyCollection<string> ReadonlyList
{
get { return _readonlyList; }
}
private List<string> _list;
public List<string> List
{
get { return _list; }
}
public AnotherClass()
{
_list = new List<string>();
_readonlyList = new ReadOnlyCollection<string>(_list);
}
}
Then any change to the List property is reflected in the ReadOnlyList property:
class Program
{
static void Main(string[] args)
{
AnotherClass c = new AnotherClass();
c.List.Add("aaa");
Console.WriteLine(c.ReadonlyList[0]); // prints "aaa"
c.List.Add("bbb");
Console.WriteLine(c.ReadonlyList[1]); // prints "bbb"
Console.Read();
}
}
You may have issues with thread safety, but exposing IEnumerable is even worse for that matter.
Personally, I use a custom IIndexable<T> interface with several handy wrapper classes and extension method that I use all over my code for immutable lists. It allows random access to list elements, and does not expose any methods for modification:
public interface IIndexable<T> : IEnumerable<T>
{
T this[int index] { get; }
int Length { get; }
}
It also allows neat LINQ-like extension methods like Skip, Take and similar, which have better performance compared to LINQ due to the indexing capability.
In that case, you can implement a projection like this:
public class ProjectionIndexable<Tsrc, Ttarget> : IIndexable<Ttarget>
{
public ProjectionIndexable
(IIndexable<Tsrc> src, Func<Tsrc, Ttarget> projection)
{
_src = src;
_projection = projection;
}
#region IIndexable<Ttarget> Members
public Ttarget this[int index]
{
get { return _projection(_src[index]); }
}
public int Length
{
get { return _src.Length; }
}
#endregion
#region IEnumerable<Ttarget> Members
// create your own enumerator here
#endregion
}
And use it like this:
class AnotherClass
{
private IIndexable<string> _readonlyList;
public IIndexable<string> ReadonlyList
{
get { return _readonlyList; }
}
private List<SomeClass> _list;
public List<SomeClass> List
{
get { return _list; }
}
public AnotherClass()
{
_list = new List<SomeClass>();
_readonlyList = new ProjectionIndexable<SomeClass, string>
(_list.AsIndexable(), c => c.Age);
}
}
[Edit]
In the meantime, I posted an article describing such a collection on CodeProject. I saw you've implemented it yourself already, but you can check it out nevertheless and reuse parts of the code where you see fit.
Why don't you just return IEnumerable?
If you have access to LINQ (.NET 3.5) then just use a select()
public IEnumerable<string> Ages{
get{
return _innerList.Select(s => s.stringProperty);
}
}
in this case I normaly just use IEnumerable - if the collection is readonly and you don't need the Index-functionality you can just do somehting like this:
public IEnumerable<string> Ages
{
get
{
return this._innerList.Select(someObj => someObj.Age).ToArray();
}
}