C#: List add object initializer - c#

Lets say I have this class:
class MyList<T>
{
}
What must I do to that class, to make the following possible:
var list = new MyList<int> {1, 2, 3, 4};

Have an Add method and implement IEnumerable.
class MyList<T> : IEnumerable
{
public void Add(T t)
{
}
public IEnumerator GetEnumerator()
{
//...
}
}
public void T()
{
MyList<int> a = new MyList<int>{1,2,3};
}

Implementing ICollection on MyList will let the initalizer syntax work
class MyList<T> : ICollection<T>
{
}
Although the bare minimum would be:
public class myList<T> : IEnumerable<T>
{
public void Add(T val)
{
}
public IEnumerator<T> GetEnumerator()
{
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
}
}

ICollection<T> is also good.

Related

Generics Interface spezialisation

I try to give my generic interface a base.
Declaration:
public interface IMyInterface
{
ObservableCollection<object> Items {get;}
}
public interface IMyInterface<TValue>
{
new ObservableCollection<TValue> Items {get;} //Try to override base Items
}
Implementation
public abstract class MyBase<T> : IMyInterface<T>
{
private ObservableCollection<T> = _Items;
public ObservableCollection<T> Items
{
get
{
return _Items;
}
}
public ObservableCollection<T> IMyInterface.Items
{
get
{
return _Items as ObservableCollection<T>; //Reason?
}
}
Usage:
void foo(object sender, NotifyCollectionChangedEventArgs e)
{
foreach(IMyInterface obj in e.NewItems) // e.NewItems are derived from MyBase
{
var item = obj.Items; // Problem: item = null
//Do something
}
}
But if i try to use it in that way, i got null.
What is my mistake? Exists any other, better ways?
Your implementation is the problem here. The cast will result in null. You can only use covariant interfaces, so the first Items should be an IEnumerable<object>:
public interface IMyInterface
{
IEnumerable<object> Items { get; }
}
public interface IMyInterface<TValue> : IMyInterface
{
new ObservableCollection<TValue> Items { get; } //Try to override base Items
}
public abstract class MyBase<T> : IMyInterface<T> where T : class
{
private ObservableCollection<T> _Items;
public ObservableCollection<T> Items
{
get
{
return _Items;
}
}
IEnumerable<object> IMyInterface.Items
{
get
{
return _Items;
}
}
}

Override IEnumerable<T> Where

I've written a class that implements IEnumerable :
public class MyEnumerable : IEnumerable<MyClass>
{
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<MyClass> GetEnumerator()
{
//Enumerate
}
}
I'd like to "override" the Where method. What I want to do is :
MyEnumerable myEnumerable = new MyEnumerable();
MyEnumerable myEnumerable2 = myEnumerable.Where(/*some predicate*/);
This is not possible for the moment because myEnumerable.Where() returns an IEnumerable.
What I want is that myEnumerable.Where() returns a MyEnumerable.
Is that possible to do this ?
Thank you
Sure - just add a Where method to MyEnumerable. The Linq Where method is an extension method, so it's not technically an override. you're "hiding" the linq method.
public class MyEnumerable : IEnumerable<MyClass>
{
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<MyClass> GetEnumerator()
{
//Enumerate
}
public MyEnumerable Where()
{
// implement `Where`
}
}
There are some caveats, though:
Your Where method will only be called if the declared type is MyEnumerable - it will not be called on variables of type IEnumerable<MyClass> (or any collection that implements it, like List<MyClass>
There are several overloads of Where that will need to be implemented as well if you want to maintain consistently with Linq.
Update
From your comment your enumerator is a lazy file enumerator and you want to be able to select items from it based on a predicate and still have the laziness.
You could create another class inheriting that class or an interface to help with this.
Here is an example
public class FileItem
{
//Some properties
}
public interface IFileEnumerator : IEnumerable<FileItem>
{
IFileEnumerator Where(Func<FileItem, bool> predicate);
}
public class FileEnumerator : IFileEnumerator
{
private readonly string fileName;
public FileEnumerator(string fileName)
{
this.fileName = fileName;
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<FileItem> GetEnumerator()
{
var items = new List<FileItem>();
//Read from file and add lines to items
return items.GetEnumerator();
}
public IFileEnumerator Where(Func<FileItem, bool> predicate)
{
return new MemoryEnumerator(ToEnumerable(GetEnumerator()).Where(predicate));
}
private static IEnumerable<T> ToEnumerable<T>(IEnumerator<T> enumerator)
{
while (enumerator.MoveNext())
{
yield return enumerator.Current;
}
}
}
public class MemoryEnumerator : IFileEnumerator
{
private readonly IEnumerable<FileItem> items;
public MemoryEnumerator(IEnumerable<FileItem> items)
{
this.items = items;
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<FileItem> GetEnumerator()
{
return items.GetEnumerator();
}
public IFileEnumerator Where(Func<FileItem, bool> predicate)
{
return new MemoryEnumerator(items.Where(predicate));
}
}

Generic extension method to convert from one collection to another

I'm working in a code base which has a lot of first class collections.
In order to ease using these collections with LINQ, there is an extension method per collection that looks like:
public static class CustomCollectionExtensions
{
public static CustomCollection ToCustomCollection(this IEnumerable<CustomItem> enumerable)
{
return new CustomCollection(enumerable);
}
}
With the accompanying constructors:
public class CustomCollection : List<CustomItem>
{
public CustomCollection(IEnumerable<CustomItem> enumerable) : base(enumerable) { }
}
This winds up being a bunch of boilerplate so I attempted to write a generic IEnumerable<U>.To<T>() so that we wouldn't have to keep generating these specific ToXCollection() methods.
I got as far as:
public static class GenericCollectionExtensions
{
public static T To<T, U>(this IEnumerable<U> enumerable) where T : ICollection<U>, new()
{
T collection = new T();
foreach (U u in enumerable)
{
collection.Add(u);
}
return collection;
}
}
Which has to be called like customCollectionInstance.OrderBy(i => i.Property).To<CustomCollection, CustomItem>()
Is there a way to avoid having to specify the CustomItem type so we can instead use customCollectionInstance.OrderBy(i => i.Property).To<CustomCollection>() or is this not something that can be done generically?
Something close to what you want:
public static class GenericCollectionExtensions
{
public sealed class CollectionConverter<TItem>
{
private readonly IEnumerable<TItem> _source;
public CollectionConverter(IEnumerable<TItem> source)
{
_source = source;
}
public TCollection To<TCollection>()
where TCollection : ICollection<TItem>, new()
{
var collection = new TCollection();
foreach(var item in _source)
{
collection.Add(item);
}
return collection;
}
}
public static CollectionConverter<T> Convert<T>(this IEnumerable<T> sequence)
{
return new CollectionConverter<T>(sequence);
}
}
Usage:
customCollectionInstance.OrderBy(i => i.Property).Convert().To<CustomCollection>();

C# Casting a List<ObjBase> as List<Obj>

Why can I not cast a List<ObjBase> as List<Obj>? Why does the following not work:
internal class ObjBase
{
}
internal class Obj : ObjBase
{
}
internal class ObjManager
{
internal List<Obj> returnStuff()
{
return getSomeStuff() as List<Obj>;
}
private List<ObjBase> getSomeStuff()
{
return new List<ObjBase>();
}
}
Instead I have to do this:
internal class ObjBase
{
}
internal class Obj : ObjBase
{
}
internal class ObjManager
{
internal List<Obj> returnStuff()
{
List<ObjBase> returnedList = getSomeStuff();
List<Obj> listToReturn = new List<Obj>(returnedList.Count);
foreach (ObjBase currentBaseObject in returnedList)
{
listToReturn.Add(currentBaseObject as Obj);
}
return listToReturn;
}
private List<ObjBase> getSomeStuff()
{
return new List<ObjBase>();
}
}
I get the following error in Visual Studio 2008 (shortened for readability):
Cannot convert type 'List' to 'List' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion
Thanks.
You can use Cast and ToList extension methods from System.Linq to have this in one line.
Instead of
internal List<Obj> returnStuff()
{
return getSomeStuff() as List<Obj>;
}
do this:
internal List<Obj> returnStuff()
{
return getSomeStuff().Cast<Obj>().ToList();
}
I can only describe the "problem" from a Java view, but from what little I know this aspect is the same in both C# and Java:
A List<ObjBase> is not a List<Obj>, because it could contain an ObjBase object which is not a Obj object.
The other way around a List<Obj> can not be cast to a List<ObjBase> because the former guarantees to accept an Add() call with a ObjBase argument, which the latter will not accept!
So to summarize: even though a Obj is-a ObjBase a List<Obj> is not a List<ObjBase>.
Please look at the following questions:
.NET Casting Generic List
Why does this generic cast fail?
Covariance my friend.
Look at http://blog.t-l-k.com/dot-net/2009/c-sharp-4-covariance-and-contravariance
list.ConvertAll looks tempting but has 1 big disadvantage: it will create a whole new list. This will impact performance and memory usage especially for big lists.
With a bit more effort you can create a wrapper list class that keeps the original list as an internal reference, and convert the items only when they are used.
Usage:
var x = new List<ObjBase>();
var y = x.CastList<ObjBase, Obj>(); // y is now an IList<Obj>
Code to add to your library:
public static class Extensions
{
public static IList<TTo> CastList<TFrom, TTo>(this IList<TFrom> list)
{
return new CastedList<TTo, TFrom>(list);
}
}
public class CastedList<TTo, TFrom> : IList<TTo>
{
public IList<TFrom> BaseList;
public CastedList(IList<TFrom> baseList)
{
BaseList = baseList;
}
// IEnumerable
IEnumerator IEnumerable.GetEnumerator() { return BaseList.GetEnumerator(); }
// IEnumerable<>
public IEnumerator<TTo> GetEnumerator() { return new CastedEnumerator<TTo, TFrom>(BaseList.GetEnumerator()); }
// ICollection
public int Count { get { return BaseList.Count; } }
public bool IsReadOnly { get { return BaseList.IsReadOnly; } }
public void Add(TTo item) { BaseList.Add((TFrom)(object)item); }
public void Clear() { BaseList.Clear(); }
public bool Contains(TTo item) { return BaseList.Contains((TFrom)(object)item); }
public void CopyTo(TTo[] array, int arrayIndex) { BaseList.CopyTo((TFrom[])(object)array, arrayIndex); }
public bool Remove(TTo item) { return BaseList.Remove((TFrom)(object)item); }
// IList
public TTo this[int index]
{
get { return (TTo)(object)BaseList[index]; }
set { BaseList[index] = (TFrom)(object)value; }
}
public int IndexOf(TTo item) { return BaseList.IndexOf((TFrom)(object)item); }
public void Insert(int index, TTo item) { BaseList.Insert(index, (TFrom)(object)item); }
public void RemoveAt(int index) { BaseList.RemoveAt(index); }
}
public class CastedEnumerator<TTo, TFrom> : IEnumerator<TTo>
{
public IEnumerator<TFrom> BaseEnumerator;
public CastedEnumerator(IEnumerator<TFrom> baseEnumerator)
{
BaseEnumerator = baseEnumerator;
}
// IDisposable
public void Dispose() { BaseEnumerator.Dispose(); }
// IEnumerator
object IEnumerator.Current { get { return BaseEnumerator.Current; } }
public bool MoveNext() { return BaseEnumerator.MoveNext(); }
public void Reset() { BaseEnumerator.Reset(); }
// IEnumerator<>
public TTo Current { get { return (TTo)(object)BaseEnumerator.Current; } }
}
I think you are misunderstanding the cast you are trying to do. You are thinking that you are changing the type of the object that is stored in the list, where you are actually trying to change the type of the list itself. It rather makes sense that you can't change the list itself as you have already populated it.
You might look at it as a list of a base class and then cast it when you are processing the list items, that would be my approach.
What is the purpose of this attempted cast?
C# currently does not support variance for generic types. From what I've read, this will change in 4.0.
See here for more information on variance in generics.
Linq has a ConvertAll method. so something like
list.ConvertAll<Obj>(objBase => objbase.ConvertTo(obj));
I'm not sure what else to suggest. I assume ObjBase is the base class, and if all ObjBase objects are Obj objects, i'm not sure why you would have the two objects in the first place. Perhaps i'm off the mark.
Edit: the list.Cast method would work better than the above, assuming they are castable to each other. Forgot about that until I read the other answers.
This is a major pain in C# - this is how generics were designed. List doesn't extend List, its just a completely different type. You can't cast or assign them to each other in any way, your only option is to copy one list to the other one.
Lazarus:
I thought that the compiler would realise that I wanted actions done on the objects of the list and not that I was trying to cast the list itself.
Some more information:
public abstract class ObjBase
{
}
internal interface IDatabaseObject
{
}
public class Obj : ObjBase, IDatabaseObject
{
}
internal interface IDatabaseObjectManager
{
List<ObjBase> getSomeStuff();
}
public class ObjManager : IObjManager
{
public List<Obj> returnStuff()
{
return getSomeStuff().Cast <Customer>().ToList<Customer>();
}
private List<ObjBase> getSomeStuff()
{
return new List<ObjBase>();
}
}
Now client code outside of this DLL can go:
ObjManager objM = new ObjManager();
List listOB = objM.returnStuff();
I'm going to be creating several Obj and ObjManager types for this part (O/RM) of the application.
(Darn comment block ran out of characters! :-)
Here is how I fixed the Conversion from a
list<SomeOtherObject>
to a
object
and then to a
List<object>
https://stackoverflow.com/a/16147909/2307326

Generic method in a non-generic class?

I'm sure I've done this before, but can't find any example of it! Grrr...
For example, I want to convert an IList<T> into a BindingList<T>:
public class ListHelper
{
public static BindingList<T> ToBindingList(IList<T> data)
{
BindingList<T> output = new BindingList<T>();
foreach (T item in data)
output.Add(item);
return output;
}
}
ToBindingList <T> (...)
public class ListHelper
{
public static BindingList<T> ToBindingList<T>(IList<T> data)
{
BindingList<T> output = new BindingList<T>();
foreach (T item in data)
{
output.Add(item);
}
return output;
}
}
Wouldn't this be simpler?
public static class Extensions
{
public static BindingList<T> ToBindingList<T>(this IList<T> list)
{
return new BindingList<T>(list);
}
}
It's so simple that we don't need an extension method ...
Am I missing something?
You can do this by extension method and it would be better.
public static class Extensions
{
public static BindingList<T> ToBindingList<T>(this IList<T> list)
{
BindingList<T> bindingList = new BindingList<T>();
foreach (var item in list)
{
bindingList.Add(item);
}
return bindingList;
}
}

Categories