Assume the following class:
public class MyEnum: IEnumerator
{
private List<SomeObject> _myList = new List<SomeObject>();
...
}
It is necessary to implement the IEnumerator methods in MyEnum.
But is it possible to 'delegate' or redirect the implementation for IEnumerator directly to _myList without needing to implement the IEnumerator methods?
Method 1:
Continue to use encapsulation and forward calls to the List implementation.
class SomeObject
{
}
class MyEnum : IEnumerable<SomeObject>
{
private List<SomeObject> _myList = new List<SomeObject>();
public void Add(SomeObject o)
{
_myList.Add(o);
}
public IEnumerator<SomeObject> GetEnumerator()
{
return _myList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
class Program
{
static void Main(string[] args)
{
MyEnum a = new MyEnum();
a.Add(new SomeObject());
foreach (SomeObject o in a)
{
Console.WriteLine(o.GetType().ToString());
}
Console.ReadLine();
}
}
Method 2:
Inherit from List implementation you get that behavior for free.
class SomeObject
{
}
class MyEnum : List<SomeObject>
{
}
class Program
{
static void Main(string[] args)
{
MyEnum a = new MyEnum();
a.Add(new SomeObject());
foreach (SomeObject o in a)
{
Console.WriteLine(o.GetType().ToString());
}
Console.ReadLine();
}
}
Method 1 allows for better sandboxing as there is no method that will be called in List without MyEnum knowledge. For least effort Method 2 is preferred.
You can do this:
public class MyEnum : IEnumerator {
private List<SomeObject> _myList = new List<SomeObject>();
public IEnumerator GetEnumerator() { return this._myList.GetEnumerator(); }
}
The reason is simple. Your class can contains several fields which are collections, so compiler/enviroment can't know which field should be used for implementing "IEnumerator".
EIDT: I agree with #pb - you should implements IEnumerator<SomeObject> interface.
Apart from using pb's method, this isn't possible for a “simple” reason: the interface method needs to get passed a this pointer as the first argument. When you call GetEnumerator on your object, this pointer will be your object. However, in order for the invocation to work on the nested list, the pointer would have to be a reference to that list, not your class.
Therefore you explicitly have to delegate the method to the other object.
(And by the way, the advice in the other reply was right: use IEnumerator<T>, not IEnumerable!)
If you want return a collection in a way where the caller is unable to modify the collection, you might want to wrap the List into a ReadOnlyCollection<> and return IEnumerable<> of the ReadOnlyCollection<>.
This way you can be sure your collection will not be changed.
Not unless you derive from List<T>.
public class MyEnum : List<SomeObject>, IEnumerable<SomeObject>{}
Thank you all for your input and explanations.
Eventually I have combined some of your answers to the following:
class MyEnum : IEnumerable<SomeObject>
{
private List<SomeObject> _myList = new List<SomeObject>();
public IEnumerator<SomeObject> GetEnumerator()
{
// Create a read-only copy of the list.
ReadOnlyCollection<CustomDevice> items = new ReadOnlyCollection<CustomDevice>(_myList);
return items.GetEnumerator();
}
}
This solution is to ensure the calling code is incapable of modifying the list and each enumerator is independant of the others in every way (e.g. with sorting).
Thanks again.
Note that thanks to duck-typing, you can use foreach on any object that has a GetEnumerator method - the object type need not actually implement IEnumerable.
So if you do this:
class SomeObject
{
}
class MyEnum
{
private List<SomeObject> _myList = new List<SomeObject>();
public IEnumerator<SomeObject> GetEnumerator()
{
return _myList.GetEnumerator();
}
}
Then this works just fine:
MyEnum objects = new MyEnum();
// ... add some objects
foreach (SomeObject obj in objects)
{
Console.WriteLine(obj.ToString());
}
Related
I got a problem in C#, giving me an error 'The type arguments for method cannot be inferred from the usage'. Seems that the compiler cannot determine the correct interface, if I derive a generic list from a non-generic one:
Code:
public class SpecialItem : BaseItem
{
public string Title { get; set; }
}
public class BaseItem
{
public string Name { get; set; }
}
public class GenericList<T> : NongenericBaseList, IEnumerable<T>
where T: BaseItem
{
public new T this[int index]
{
get { return _items[index] as T; }
}
public new IEnumerator<T> GetEnumerator()
{
var iter = _items.GetEnumerator();
while (iter.MoveNext())
{
yield return iter.Current as T;
}
}
}
public class NongenericBaseList : IEnumerable<BaseItem>
{
protected List<BaseItem> _items;
public BaseItem this[int index]
{
get { return _items[index]; }
}
public IEnumerator<BaseItem> GetEnumerator()
{
return _items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Usage:
var genericList = new GenericList<SpecialItem>();
foreach (var item in genericList) // Uses IEnmerable<SpecialItem>, OK!
{
Console.WriteLine(item.Title);
}
var l = genericList.ToList(); // ERROR!
The ForEarch gets the correct Enumerator (SpecialItem), but the lambda does not know what to use (IEnumerable<BaseItem> or IEnumerable<SpecialItem>).
What to do? How can I set IEnumerable<SpecialItem> as 'default' interface? I dont want to explicetly code the type all the time like this:
var l = genericList.ToList<SpecialItem>();
First of all: kudos for providing a self-contained example!
You cannot specify a 'default' interface for type inference. The argument type for ToList<T> cannot be resolved because it is ambiguous, the type implements both IEnumerable<BaseItem> and IEnumerable<SpecialItem>, and both versions are applicable.
Is there a possibility to remove the class NongenericBaseList completely, and use the GenericList<T>instead? That would solve your problem; you can use GenericList<BaseItem> instead of NongenericBaseList
Another option is to reverse the inheritance; make NongenericBaseList empty and deriving from GenericList<BaseItem>.
Thanks to Sriram Sakthivel, he guided me to a solution with a very small overhead. To make things clear I wanted to make sure that:
Both lists, the generic and nongeneric one must be the same object. Therefore I have to derive, not packing in a wrapper.
Both lists must support access via loops (ForEach) and lambdas / extension methods without the need to explicitly typing the class name.
They have to implement IList<T>, so T out is not an option.
In short, the following code must compile without errors:
// Generic
var genericList = new GenericList<SpecialItem>();
foreach (var item in genericList)
{
Console.WriteLine(item.Title);
}
var l = genericList.ToList();
// Nongeneric
var nongenericList = genericList as NongenericBaseList;
foreach (var item in nongenericList)
{
Console.WriteLine(item.Name);
}
var nl = nongenericList.ToList();
I came to the conclusion, that this is not possible with the upper code (correct me if that is not true!). The loops are working fine, but either the generic or the nongeneric list does not work with .ToList() or other extension methods, because the compiler cannot inferre the type.
Now I used Sriram Sakthivel tipp, implementing only IEnumerable without <T>. But that allone would make it impossible to use extension methods at all even if you explicitely write the type.
I simply added a property, casting the collection:
public class NongenericBaseList : IEnumerable // Without the T!
{
protected List<BaseItem> _items;
// The property
public IEnumerable<BaseItem> L
{
get { return this as IEnumerable<BaseItem>; }
}
public BaseItem this[int index]
{
get { return _items[index]; }
}
public IEnumerator<BaseItem> GetEnumerator()
{
return _items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Now I can type:
var nl = nongenericList.L.ToList();
Any better solution would be appreciated!
I have a problem with the generic class. I have something like this:
public abstract class IGroup<T> : IEnumerable where T : class {
protected List<T> groupMembers;
protected List<IGameAction> groupIGameActionList;
public IGroup() {
groupMembers = new List<T>();
groupIGameActionList = new List<IGameAction>();
//groupIGameActionList.Add(new DieGameAction(groupMembers));
}
}
And second class:
class DieGameAction : IGameAction {
List<object> gameObjectList;
public DieGameAction(List<object> objectList) {
gameObjectList = objectList;
}
}
I don't know how to cast or convert groupMembers in commented line. This doesn't work because it can not be converted (List<T> to List<object>). So how can I do it?
groupMembers.Cast<object>().ToList();
But that doesn't look a good thing to do. You are creating a new empty list that will not be related to the original anymore.
The way you're gonna be using these classes will tell if that would be a good idea.
If you're planning to have both lists updated by adding items to a single class, it will not fit. Then maybe your DieGameAction should be generic as well: DieGameAction<T>.
Then you could give the original list without casting.
But, there's another danger: if you set a new list to the IGroup, it will not be reflected to DieGameAction.
So, it all depends on what you're trying to do.
Old question but by declaring your variable as IList instead of List<object>, you can assign a list (or array) of any type to the variable and simply cast it to List<Whatever> later (of course it's going to throw an exception if you cast it to a wrong type). I have found this more efficient than having to do .Cast<object>() every time you want to assign something to the variable.
I'm going to focus only on providing a solution.
You can make DieGameAction use IList < object > instead:
class DieGameAction : IGameAction {
IList<object> gameObjectList;
public DieGameAction(IList<object> objectList) {
gameObjectList = objectList;
}
}
Then you can provide an IList < object > implementation which adapts any IList < T >.
public abstract class IGroup<T> : IEnumerable where T : class {
protected List<T> groupMembers;
protected List<IGameAction> groupIGameActionList;
public IGroup() {
groupMembers = new List<T>();
groupIGameActionList = new List<IGameAction>();
groupIGameActionList.Add(new DieGameAction(new ObjectListAdapter<T>(groupMembers)));
}
}
I'm going to try and provide one of the many possible solutions using as base the System.Collections.ObjectModel.Collection < T > which can also wrap an IList < T >:
public class ObjectListAdapter<T> : System.Collections.ObjectModel.Collection<T>, IList<object>
{
public ObjectListAdapter(IList<T> wrappedList)
: base(wrappedList)
{
}
public int IndexOf(object item)
{
return base.IndexOf((T)item);
}
public void Insert(int index, object item)
{
base.Insert(index, (T)item);
}
public new object this[int index]
{
get
{
return base[index];
}
set
{
base[index] = (T)value;
}
}
public void Add(object item)
{
base.Add((T)item);
}
public bool Contains(object item)
{
return base.Contains((T)item);
}
public void CopyTo(object[] array, int arrayIndex)
{
this.Cast<object>().ToArray().CopyTo(array, arrayIndex);
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(object item)
{
return base.Remove((T)item);
}
public new IEnumerator<object> GetEnumerator()
{
return this.Cast<object>().GetEnumerator();
}
}
The list changes will throw a type casting exception upon trying to use an unsupported object, the way I programmed it over here, but you can also handle that as you like.
Now, for IList < object > you could also try using IList instead which is also implemented by List < T > so you'll basically have to do nothing more to get this working.
Note that the important thing is that the list will appear the same at both places used since they will basically be using the same underlying List object.
Let me know if this answers your question, by marking it as an answer, or not to refrain :)
I just faced the same problem which led me here. The solution that worked for me was to cast into IEnumerable of Object instead of List of Object
(System.Collections.Generic.IEnumerable<object>)groupMembers;
I had similar issue today but i called the LINQ .ToArray() on it directly and it works fine. that should be shorter than casting.
so you could say
groupMembers.ToArray();
It worked for me like this:
List<myclass> listMyclass = new List<myclass>();
var listObject = listMyclass.ToList<object>();
I've been around this design problem many times, and never found a killer solution.
I want to expose a collection that is editable in the owner class scope, but only readable for other public scopes.
Trial 1:
public class MyClass
{
private List<object> _myList = new List<object>();
public IEnumerable<object> MyList { get { return _myList; } }
}
The problem with this is a external code can just cast it back to List and edit, like this:
var x = ((List<object>)MyList);
Trial 2:
public class MyClass
{
private List<object> _myList = new List<object>();
public IEnumerable<object> MyList { get { return _myList.ToList(); } }
}
This way we prevent external modification, but create a unnecessary overhead of copying the List many times.
Trial 3:
public class MyClass
{
private List<object> _myList = new List<object>();
private ReadOnlyCollection<object> _roList =
new ReadOnlyCollection<object>(_myList)
public IEnumerable<object> MyList { get { return _roList; } }
}
This is the standard solution, wich I use currently, but ReadOnlyCollection is about 30% slower:
Debug Trace:
Use normal foreach on the ReadOnlyCollection
Speed(ms): 2520,3203125
Result: 4999999950000000
use<list>.ForEach
Speed(ms): 1446,1796875
Result: 4999999950000000
Use normal foreach on the List
Speed(ms): 1891,2421875
Result: 4999999950000000
Is there a 'perfect' way of doing this? Thanks.
Have you tried returning the enumerator?
public class MyClass
{
private List<object> _myList = new List<object>();
public IEnumerable<object> MyList { get { yield return _myList.GetEnumerator(); } }
}
This doesn't create a copy, is readonly, and cannot be cast back to list.
Edit: this only works with yield return. It is lazy evaluated this way, I do not know whether that is an issue for you or not.
You can use List<T>.AsReadOnly method to expose a thin read-only wrapper of your list. There will be no additional copying, and the caller will "see" changes to the original array done inside your method instantaneously:
public ReadOnlyCollection<object> MyList { get { return _myList.AsReadOnly(); } }
List<T> implements IReadOnlyList<T>:
public class MyClass
{
private List<object> _myList = new List<object>(); // Modifiable
public IReadOnlyList<object> MyList => _myList; // Read only
}
The solution I usually use and like a lot because it is simple is the following one:
public IEnumerable<object> MyList { get { return _myList.Select(x => x); } }
However, it requires you to use a version of .NET that supports Linq
For looping over it with a foreach it's actually faster: less than 1ms for the Select and 0.1 second for the ReadOnlyCollection. For the ReadOnlyCollection, I used:
public IEnumerable<object> MyROList { get { return new ReadOnlyCollection<object>(_myList); } }
Use ReadOnlyCollection<T> as a wrapper - it uses your List<T> collection internally (using the same reference, so it doesn't copy anything, and any changes made to the List are also reflected in the ReadOnlyCollection).
It's better than just offering an IEnumerable property because it also offers indexing and count information.
.NET Framework 4.5 introduces two new interfaces: IReadOnlyCollection<T> and IReadOnlyList<T>. List<T> implements both interfaces.
Why don't you use List<T>.AsReadOnly method, see the code snippet below:
public class MyClass
{
private List<object> _myList = new List<object>();
public IList<object> MyList { get { return _myList.AsReadOnly(); } }
}
I'm trying to create a class that accepts a constructor similar to that of a dictionary, list, or array where you can create the object with a literal collection of objects, though I have been unable to find how to create such a constructor, if it's even possible.
MyClass obj = new MyClass()
{
{ value1, value2 },
{ value3, value4 }
}
You need two things to make collection initializers work:
Implement IEnumerable (non-generic version)
Add() method that matches the collection initializer
Here's an example that looks like IDictionary:
class Program
{
static void Main(string[] args)
{
MyClass obj = new MyClass()
{
{value1, value2},
{value3, value4}
};
}
}
public class MyClass : IEnumerable
{
public void Add(object x, object y)
{
}
public IEnumerator GetEnumerator()
{
}
}
Note that the collection initializer code literally translates to this:
MyClass temp = new MyClass();
temp.Add(value1, value2);
temp.Add(value3, value4);
MyClass obj = temp;
Because of the temp variable, if any of the Add() calls generate an exception, the named variable (obj in this case) is never actually assigned. Interestingly, this also means that if MyClass were to implement IDisposable, then Dispose() would not get called on the constructed object when one of the Add() methods generates an error (I tested this to be sure).
Why require IEnumerable? Because that interface differentiates classes with Add for collections and classes with Add for calculations.
http://blogs.msdn.com/b/madst/archive/2006/10/10/what-is-a-collection_3f00_.aspx
[when you analyze classes with Add] you realize that there are essentially two fundamentally different meanings of the name “Add”:
a) Insert the argument into a collection, or
b) Return the arithmetic sum of the argument and the receiver
Also note that if your collection class implements IDisposable, then you should not use collection initializers if there is any chance that Add() will throw an exception or if any of the expressions being fed to Add() can throw an exception.
https://connect.microsoft.com/VisualStudio/feedback/details/654186/collection-initializers-called-on-collections-that-implement-idisposable-need-to-call-dispose-in-case-of-failure#
How about a variable constructor:
public class MyClass
{
public MyClass() {}
public MyClass(params object[] list) { ... }
}
Isn't the default good enough ?
new MyClass {
MyCol = {Value1, Value2, ... },
};
I know there are very similar questions but im not sure that any of them are exactly what i need. I have 2 methods that do exactly the same thing (so i dont need to override or anything) the only difference is the parameter and return types.
public List<List<TestResult>> BatchResultsList(List<TestResult> objectList)
{
}
public List<List<ResultLinks>> BatchResultsList(List<ResultLinks> objectList)
{
}
is there a neat way of doing this that doesnt involve duplciate code (the types are used inside the method).
public List<List<T>> BatchResultsList<T>(List<T> objectList)
{
foreach(T t in objectList)
{
// do something with T.
// note that since the type of T isn't constrained, the compiler can't
// tell what properties and methods it has, so you can't do much with it
// except add it to a collection or compare it to another object.
}
}
and if you need to limit the type of T so that you'll only process specific sorts of objects, make both TestResult and ResultLinks implement an interface, say, IResult. Then:
public interface IResult
{
void DoSomething();
}
public class TestResult : IResult { ... }
public class ResultLinks : IResult { ... }
public List<List<T>> BatchResultsList<T>(List<T> objectList) where T : IResult
{
foreach(T t in objectList)
{
t.DoSomething();
// do something with T.
// note that since the type of T is constrained to types that implement
// IResult, you can access all properties and methods defined in IResult
// on the object t here
}
}
When you call the method, you can of course omit the type parameter, since it can be inferred:
List<TestResult> objectList = new List<TestResult>();
List<List<TestResult>> list = BatchResultsList(objectList);
use generic methods
public List<List<T>> BatchResultsList<T>(List<T> objectList)
{
}
when you call it for TestResult:
BatchResultsList<TestResult>(testResultList)
for ResultLinks:
BatchResultsList<ResultLinks>(resultLinksList)
EDIT:
I presume that because it's the same code inside you 2 methods, TestResult & ResultLinks must implement a common interface, let's call it SomeInterface & a common constructor, let's choose the parameterless one:
you would declare and use the method like this:
public List<List<T>> BatchResultsList<T>(List<T> objectList)
where T:SomeInterface, new()
{
List<List<T>> toReturn = new List<List<T>>();
//to instantiate a new T:
T t = new T();
foreach (T result in objectList)
{
//use result like a SomeInterface instance
}
//...
return toReturn;
}
what about
public List<IList> BatchResultsList(List<IList> objectList)
{
}
Generic version:
public List<List<T>> BatchResultsList<T>(List<T> objectList){}