Making a generic Class IEnumerable - c#

I have a generic class which uses a type parameter
public class CustomClass<T>
and I am using it with an ObservableCollection<someClass> Type. All I want is to make this class implement the IEnumerable interface, so I did the following:
public class CustomClass<T> : IEnumerable
#region Variable Declarations
...
#endregion
#region Constructor and CustomClass<T> properties and methods
...
#endregion
#region Here I add the code for IEnumerable to work
private T theObservableCollection
{
get
{
if (typeof(T) == typeof(ObservableCollection<someClass>))
return theObservableCollection;
else
return default(T);
}
}
//Create a public GetEnumerator method, the basic ingredient of an IEnumerable interface.
public IEnumerator GetEnumerator()
{
IEnumerator r = (IEnumerator)new SettingEnumerator(this);
return r;
}
//Create a nested-class
class SettingEnumerator
{
int index;
CustomClass<T> sp;
public SettingEnumerator(CustomClass<T> str_obj)
{
index = -1;
sp = str_obj;
}
public object Current
{
get
{
return sp.theObservableCollection[index];
}
}
public bool MoveNext()
{
if (index < sp.theObservableCollection.Length - 1)
{
index++;
return true;
}
return false;
}
public void Reset()
{
index = -1;
}
}
#endregion
The compiler complains:
Cannot apply indexing with [] to an expression of type 'T'
I understand that there is something wrong there, but I don't know how to accomplish what I want, which finally is to successfully make
public class CustomClass<T>
a
public class CustomClass<T> : IEnumerable

Try implementing IEnumerable<T> rather than IEnumerable

You have to specify that T can be indexed :
public class CustomClass<T> : IEnumerable where T : IList

Related

Check if generic parameter of a class implements an interface

I have a following generic class:
public class SearchResult<T>
{
public int ResultCount { get; set; }
public IEnumerable<T> Result { get; set; }
}
I also have a Bird class, which implements IFlyble interface:
public class Bird : IFlyable
{
public void Fly() {}
}
public interface IFlyable
{
void Fly();
}
I also have a variable res of type object.
How do I check if res is a SearchResult<IFlyable> ?
I tryied this way:
if (res.GetType().IsAssignableFrom(typeof(SearchResult<IFlyable>)))
{
///
}
And this way:
if(res is SearchResult<IFlyable>)
{
///
}
But it does not seems to work.
The problem you are having is probably due to the fact that SearchResult<Bird> is not convertible to SearchResult<IFlyable> because SearchResult<T> is invariant in T.
C# only admitís generic type variance in interfaces and delegates. You need to define an ISearchResult<> interface that is covariant in its generic type.
In your case, if it’s accepatable that T Is only used as an output you could define such interface as follows:
public interface ISearchResult<out T>
{
int ResultCount { get; }
IEnumerable<T> Result { get; }
}
And now a ISearchResult<Bird> is a ISearchResult<IFlyable> because you’ve given the compiler enough information so that it can verify that the conversion is in fact safe
You can also try this using reflection, which also works and no need to create another interface.
static void Main()
{
var sr = new SearchResult<Bird>();
Console.WriteLine(IsSearchResultIFlyable(sr.GetType())
? "sr is SearchResult<IFlyable>"
: "sr is Not SearchResult<IFlyable>");
Console.ReadLine();
}
public static bool IsSearchResultIFlyable(Type t)
{
if (!t.IsGenericType) return false;
if (t.GetGenericTypeDefinition() != typeof(SearchResult<>)) return false;
var gr = t.GetGenericArguments();
return gr.Length == 1 && typeof(IFlyable).IsAssignableFrom(gr[0]);
}

How to use Except operator on non generic ICollection?

I have auto generated by the VS wrapper for WMI collection witch looks like this:
// Enumerator implementation for enumerating instances of the class.
public class DiskDriveCollection : object, ICollection {
private ManagementObjectCollection privColObj;
public DiskDriveCollection(ManagementObjectCollection objCollection) {
privColObj = objCollection;
}
public virtual int Count {
get {
return privColObj.Count;
}
}
public virtual bool IsSynchronized {
get {
return privColObj.IsSynchronized;
}
}
public virtual object SyncRoot {
get {
return this;
}
}
public virtual void CopyTo(System.Array array, int index) {
...
}
public virtual System.Collections.IEnumerator GetEnumerator() {
return new DiskDriveEnumerator(privColObj.GetEnumerator());
}
public class DiskDriveEnumerator : object, System.Collections.IEnumerator {
private ManagementObjectCollection.ManagementObjectEnumerator privObjEnum;
public DiskDriveEnumerator(ManagementObjectCollection.ManagementObjectEnumerator objEnum) {
privObjEnum = objEnum;
}
public virtual object Current {
get {
return new DiskDrive(((System.Management.ManagementObject)(privObjEnum.Current)));
}
}
public virtual bool MoveNext() {
return privObjEnum.MoveNext();
}
public virtual void Reset() {
privObjEnum.Reset();
}
}
}
How can I use except operator with this non generic ICollection?
ICollection inherits from IEnumerable, and there is an OfType method which takes an IEnumerable and returns IEnumerable<T>, then you can easily use all LINQ methods when you got IEnumerable<T>, for example:
myCollection.OfType<object>()
.Except(myOtherCollection.OfType<object>(), new CustomEqualityComparer());
Since you have objects, you need to implement an equality comparer for them an pass it to Except method, otherwise Except will compare your object by references.

Read only List<T> view and covariance

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;

Cast issues between generic list and CollectionDataContract

I have the following collection contract defined:
[CollectionDataContract(Name = "Centres")]
public class Centres : List<Centre>
{}
and the following operation contract defined to return this collection
public Model.Centres GetCentres()
{
List<Centre> allCentres = (from c in Model.Centre.GetCentres()
where c.Visible == true
select c).ToList();
return allCentres
}
But when I run the code I receive an ExplicitCastException. So as far as I can see I'm trying to cast a list of centres (List) into my collection 'Centres' which itself derives from List. Is this possible or by deriving a new object am I creating a new type of list that won't work in this way.
My current work around for this problem is to declare a new instance of Centres and copy all centres into it using a foreach.
The problem is Centres "is a" List<Centre>, List<Centre> is not a Centres.
Despite Centres having no implementation it is still a sub-class of List<Centre>, you could extend your Centres class to have an implicit conversion operator or, perhaps add a constructor to Centres that takes a List<Centre> as a parameter.
Try changing Centres to somthing like ...
[CollectionDataContract(Name = "Centres")]
public class Centres : List<Centre>
{
public static implicit operator Centres(List<Centre> l)
{
Centres newCentres = new Centres();
newCentres.AddRange(l);
return newCentres;
}
}
Then it will allow implicit conversion from List<Centre>.
What you are trying wont work.
If possible you should consider refactoring Centres to a has a List<Centre> more than is a relationship or at least define a constructor that takes an IEnumerable<Centre>
This way you would be able to write:
Centres allCentres = new Centres(from c in Model.Centres.GetCentres()
where c.Visible == true
select c);
Of course it all depends on your specific situation where this might not be a valid solution.
What you can do is create your own implementation of the IList<T> interface that wraps an IList.
It takes more code, but will not be as slow as to copy all the objects:
[CollectionDataContract(Name = "Centres")]
public class Centres : IList<Centre>
{
private IList<Centre> _inner;
private IList<Centre> Inner
{
get
{
if (_inner == null)
_inner = new List<Centre>();
return _inner;
}
}
public Centres(List<Centre> items)
{
_inner = items;
}
#region IList<Centre> Members
public int IndexOf(Centre item)
{
return Inner.IndexOf(item);
}
public void Insert(int index, Centre item)
{
Inner.Insert(index, item);
}
public void RemoveAt(int index)
{
Inner.RemoveAt(index);
}
public Centre this[int index]
{
get
{
return Inner[index];
}
set
{
Inner[index] = value;
}
}
#endregion
#region ICollection<Centre> Members
public void Add(Centre item)
{
Inner.Add(item);
}
public void Clear()
{
Inner.Clear();
}
public bool Contains(Centre item)
{
return Inner.Contains(item);
}
public void CopyTo(Centre[] array, int arrayIndex)
{
Inner.CopyTo(array, arrayIndex);
}
public int Count
{
get { return Inner.Count; }
}
public bool IsReadOnly
{
get { return Inner.IsReadOnly; }
}
public bool Remove(Centre item)
{
return Inner.Remove(item);
}
#endregion
#region IEnumerable<Centre> Members
public IEnumerator<Centre> GetEnumerator()
{
return Inner.GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return Inner.GetEnumerator();
}
#endregion
}

C# - Can a List<MyClass> be seamlessly cast to a List<Interface> or similar?

I have a DataSource in my control which is always a List<T> where T has to inherit from IEntity.
public class MyClass<T> where T : IEntity
{
public List<T> DataSource
{
get;
set;
}
}
Now, obviously you can't cast a List<T> to a List<IEntity> doing the following:
List<IEntity> wontWork = (List<IEntity>)this.DataSource;
How can I get the DataSource as a List of IEntity, whilst still being able to add and remove items from the DataSource? I.e. I could do the following, but removing from the List it returns would not remove from the DataSource:
public List<TOut> GetDataSourceCopyAsUnderlyingType<TOut>()
{
if (this.DataSource == null)
{
return new List<TOut>();
}
else
{
// Get the list and the enumerator
IList list = (IList)this.DataSource;
IEnumerator enumerator = list.GetEnumerator();
// Build the target list
List<TOut> targetList = new List<TOut>();
int i = 0;
while (enumerator.MoveNext())
{
TOut entity = (TOut)list[i];
targetList.Add(entity);
i++;
}
return targetList;
}
}
Basically, I need some way of doing the following:
List<IEntity> interfaceList = this.GetDataSourceAsAnotherType<IEntity>();
int dataSourceCount = this.DataSource.Count; // Equals 5
int interfaceCount = interfaceList.Count; // Equals 5
interfaceList.RemoveAt(0);
int dataSourceCount = this.DataSource.Count; // Equals 4
int interfaceCount = interfaceList.Count; // Equals 4
And just to add, I don't mind if it means I've got to use a different type instead of a List.
EDIT: Sorry, forgot to say I'm using .Net2.0 and cannot move to .Net 3.5.
It would be a monumentally bad idea if this were allowed, which is why it isn't. I can add any old IEntity to a List<IEntity> which will blow up if that IEntity can't be cast to T. Whilst all Ts are IEntities, not all IEntities are Ts.
This works with arrays because arrays have a deliberate subtyping hole (as they do in Java). Collections do not have a subtyping hole.
Create a wrapper class that seamlessly converts. Untested sample:
public class CastList<TTarget, TOriginal>
: IList<TTarget> where TOriginal : TTarget
{
List<TOriginal> _orig;
public CastList(List<TOriginal> orig) { _orig = orig; }
public Add(TTarget item) { _orig.Add(item); }
public TTarget this[int i]
{
get { return (TTarget)_orig[i]; }
set { _orig[i] = value; }
}
public IEnumerator<TTarget> GetEnumerator()
{
foreach(TOriginal item in _orig)
yield return (TTarget)item;
}
// etc...
}
Manipulations of the original list will also be reflected in the wrapper. To use this, just construct it with your DataSource.
What DrPizza said, but with more code:
public class ListFacade<TIn, TOut> : IList<TOut> where TIn : TOut
{
private readonly IList<TIn> innerList;
public ListFacade(IList<TIn> innerList)
{
this.innerList = innerList;
}
public int Count
{
get { return this.innerList.Count; }
}
public bool IsReadOnly
{
get { return this.innerList.IsReadOnly; }
}
public TOut this[int index]
{
get { return this.innerList[index]; }
set { this.innerList[index] = (TIn)value; }
}
public void Add(TOut item)
{
this.innerList.Add((TIn)item);
}
public void Clear()
{
this.innerList.Clear();
}
public bool Contains(TOut item)
{
return (item is TIn) && this.innerList.Contains((TIn)item);
}
public void CopyTo(TOut[] array, int arrayIndex)
{
var inArray = new TIn[this.innerList.Count];
this.innerList.CopyTo(inArray, arrayIndex);
Array.Copy(inArray, array, inArray.Length);
}
public IEnumerator<TOut> GetEnumerator()
{
foreach (var item in this.innerList)
{
yield return item;
}
}
System.Collections.IEnumerator
System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public int IndexOf(TOut item)
{
return (item is TIn) ? this.innerList.IndexOf((TIn)item) : -1;
}
public void Insert(int index, TOut item)
{
this.innerList.Insert(index, (TIn)item);
}
public bool Remove(TOut item)
{
return (item is TIn) && this.innerList.Remove((TIn)item);
}
public void RemoveAt(int index)
{
this.innerList.RemoveAt(index);
}
Add, Insert and the indexer set will blow up if the argument is not of type TIn.
ok this might be completely beside the point but, how about using a little bit of Linq?
var interfaceList = objectList.ConvertAll<Interface>(o => (Interface)o);
this way you can cast the objectList easily.
hope this helps to find the solution...
I'm in favor of linq too, but you can do it like:
var interfaceList = objectList.Cast<IEntity>();
Which is shorter and more expressive.

Categories

Resources