I got following error at returns lines:
"Cannot implicity convert type using System.Collections.Generic.List<T> to T"
I do not understand why this error is thrown, my return type is IEnumerable, can you see error here?
public static IEnumerable<T> Batch<T>(this IEnumerable<T> collection, int batchSize)
{
List<T> nextbatch = new List<T>(batchSize);
foreach (T item in collection)
{
nextbatch.Add(item);
if (nextbatch.Count == batchSize)
{
yield return nextbatch;
nextbatch = new List<T>(batchSize);
}
}
if (nextbatch.Count > 0)
yield return nextbatch;
}
You're not saying "this method will return many collections of T", you're saying "this method will return many T's".
In other words, this is how you need to declare your method:
public static IEnumerable<IEnumerable<T>> Batch<T>(...)
^---notice 2 layers---^
However, assuming this method will always return lists that you don't want to retain ownership to, you should make it easier for the consumers by just stating the best type to begin with:
public static IEnumerable<List<T>> Batch<T>(...)
Method return type is IEnumerable<T> with yield should return T not List<T>
for more information on how to use yield yield
Related
I'm working in C# with the latest build of Unity3D and MonoDevelop (I believe C# version 6 is currently used in Unity but I may be wrong).
My current situation is, I have a wrapper class for a 2D array and I'd like to be able to iterate over it with a foreach like I would over a regular 2D array.
public class CoordArray<T> : IEnumerable<T> {
// ... some other members
private T[,] arr;
public CoordArray(int width, int height) {
// ... other intialization
arr = new T[height, width];
}
public IEnumerator<T> GetEnumerator() {
return arr.GetEnumerator();
}
...
}
public class Foo {
public void Bar() {
CoordArray<Poop> array = new CoordArray<Poop>(23,213);
foreach(Poop p in array) DoSomething(p);
}
}
This GetEnumerator() method, however, throws the following error in Unity:
Cannot implicitly convert type System.Collections.IEnumerator to System.Collections.Generic.IEnumerator<T>. An explicit conversion exists (are you missing a cast?)
I've found a few solutions to similar problems on this site and I've tried:
public IEnumerator<T> GetEnumerator() {
return ((IEnumerable<T>) arr).GetEnumerator();
}
but this again gives me an error:
Cannot convert type T[,] to System.Collections.Generic.IEnumerable<T>
I've also tried:
public IEnumerator<T> GetEnumerator() {
return (IEnumerator<T>) arr.GetEnumerator();
}
,
public IEnumerator<T> GetEnumerator() {
return arr.Cast<T>().GetEnumerator();
}
and:
public IEnumerator<T> GetEnumerator() {
foreach (T element in arr) yield return element;
}
but these all throw the following error:
CoordArray<T> does not implement interface member System.Collections.IEnumerable.GetEnumerator() and the best implementing candidate CoordArray<T>.GetEnumerator() return type System.Collections.Generic.IEnumerator<T> does not match interface member return type System.Collections.IEnumerator
and if I try:
public IEnumerator GetEnumerator() {
return arr.GetEnumerator();
}
the exact opposite error is thrown:
CoordArray<T> does not implement interface member System.Collections.Generic.IEnumerable<T>.GetEnumerator() and the best implementing candidate CoordArray<T>.GetEnumerator() return type System.Collections.IEnumerator does not match interface member return type System.Collections.Generic.IEnumerator<T>
and (quite obviously) it won't let me implement IEnumerator GetEnumerator() and IEnumerator<T> GetEnumerator() simultaneously.
Is there a way to get a generic iterator from a generic array?
The problem is that 2d array only "implements" the non generic IEnumerable. But you could use Cast method to get IEnumerable<T> and then get the IEnumerator<T> from it:
public IEnumerator<T> GetEnumerator()
{
return arr.Cast<T>().GetEnumerator();
}
Make sure you have included
using System.Linq;
If for some reason Cast method is not available, then I guess at least you can use C# iterator method (available since 2.0):
public IEnumerator<T> GetEnumerator()
{
foreach (T element in arr)
yield return element;
}
Update: The new compiler error you are getting is different. The above solves the implementation of the generic IEnumerable<T>.GetEnumerator() method which I think is the target of your question. But since IEnumerable<T> inherits IEnumerable, you also need to implement the non generic GetEnumerator method in your class as well (I was assuming you already did that). It needs to be implemented explicitly, so add the following to your class:
IEnumerator IEnumerable.GetEnumerator()
{
return arr.GetEnumerator();
}
Would something like this suit your needs?
public class CoordArray<T> : IEnumerable<T>
{
// ... some other members
private T[,] arr;
public CoordArray(int width, int height)
{
// ... other intialization
arr = new T[height, width];
}
private IEnumerable<T> ArrAsEnumerableT
{
get
{
foreach (var elmt in arr)
yield return elmt;
}
}
public IEnumerator<T> GetEnumerator()
{
return ArrAsEnumerableT.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ArrAsEnumerableT.GetEnumerator();
}
}
I have an extension method that works on any class, but I want to call a special version if I am working on IEnumerable<T>.
For Example
public static class ExtensionMethods
{
public static dynamic Test<T>(this T source)
{
dynamic expandoObject = new System.Dynamic.ExpandoObject();
var dictionary = (IDictionary<string,object>)expandoObject;
dictionary["Test"] = source.ToString();
return dictionary;
}
public static IEnumerable<dynamic> Test<T>(this List<T> source)
{
var result = new List<dynamic>();
foreach(var r in source)
yield return r.Test();
}
public static IEnumerable<dynamic> Test<T>(this IEnumerable<T> source)
{
var result = new List<dynamic>();
foreach(var r in source)
yield return r.Test();
}
}
// Usage
public class X
{
string guid = Guid.NewGuid().ToString();
}
void Main()
{
List<X> list = new List<X>() { new X() };
list.Test().Dump(); // Correct but only works because there is an explicit overload for List<T>
var array = list.ToArray();
((IEnumerable<X>) array).Test().Dump(); // Correct
array.Test().Dump(); // Calls the wrong extension method
}
Is there any way I can get array.Test() to call the IEnumerable version without having to explicitly cast it?
Alternatively, if I give the extension method different names, if there any way I can get a compiler error if I accidently use the wrong one?
I think you are trying to solve it in a wrong direction. The List implements IEnumerable interface and as such the compiler can have problem with solving the best method will be invoked on List. What you could do -- you could test if the IEnumerable is a list inside the extension method.
public static IEnumerable<dynamic> Test<T>(this IEnumerable<T> source)
{
if (source is List<T>) {
// here
}
var result = new List<dynamic>();
foreach(var r in source)
yield return r.Test();
}
You can specify T and not rely on type inference, this will hint compiler to use correct extension method. Code would look like this:
var array = list.ToArray();
array.Test<X>().Dump();
What happens is, that compiler cannot tell which extension to use, since Array is valid argument for both method signatures:
public static dynamic Test<T>(this T source) { .. }
public static IEnumerable<dynamic> Test<T>(this IEnumerable<T> source) { .. }
In first case compiler can assume T is of type Array. Because of it, compiler has to picks one (might be first defined?).
Add this extension method to explicitly catch all array types:
public static IEnumerable<dynamic> Test<T>(this T[] source)
{
var result = new List<dynamic>();
foreach(var r in source)
yield return r.Test();
}
I know when Linq's Any() extension is used to determine if an enumerable has at least one element it will only consume a single element. But how does that work actually? Does it have to cast all items in the enumerable first, or does it just cast them one at a time, starting with the first and stopping there?
Any() works on an IEnumerable<T> so no cast is required. It's implementation is very simple, it simply iterates through the enumerable and sees if it can find any elements matching the specified criteria.
Simple implementation looks like:
public bool Any<T>(IEnumerable<T> list)
{
using (var enumerator = list.GetEnumerator())
{
return enumerator.MoveNext();
}
}
So, no any casting required
Code in the public static class Enumerable:
public static bool Any<TSource>(this IEnumerable<TSource> source) {
if(source==null) {
throw Error.ArgumentNull("source");
}
using(IEnumerator<TSource> enumerator=source.GetEnumerator()) {
if(enumerator.MoveNext()) {
return true;
}
}
return false;
}
public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
if(source==null) {
throw Error.ArgumentNull("source");
}
if(predicate==null) {
throw Error.ArgumentNull("predicate");
}
foreach(TSource local in source) {
if(predicate(local)) {
return true;
}
}
return false;
}
Not seen the casting, but generic.
What is Linq actually doing?
(I'm assuming this is for LINQ to Objects. Anything else will be implemented differently :)
It's just returning everything from the first, and then everything from the second. All data is streamed. Something like this:
public static IEnumerable<T> Concat(this IEnumerable<T> source1,
IEnumerable<T> source2)
{
if (source1 == null)
{
throw new ArgumentNullException("source1");
}
if (source2 == null)
{
throw new ArgumentNullException("source1");
}
return ConcatImpl(source1, source2);
}
private static IEnumerable<T> ConcatImpl(this IEnumerable<T> source1,
IEnumerable<T> source2)
{
foreach (T item in source1)
{
yield return item;
}
foreach (T item in source2)
{
yield return item;
}
}
I've split this into two methods so that the argument validation can be performed eagerly but I can still use an iterator block. (No code within an iterator block is executed until the first call to MoveNext() on the result.)
It enumerates each collection in turn, and yields each element. Something like that :
public static IEnumerable<T> Concat<T>(this IEnumerable<T> source, IEnumerable<T> other)
{
foreach(var item in source) yield return item;
foreach(var item in other) yield return item;
}
(if you look at the actual implementation using Reflector, you will see that the iterator is actually implemented in a separate method)
It depends on the LINQ provider you are using. LinqToSql or L2E might use a database UNION, whereas LINQ to Objects might just enumerate both collections for your in turn.
I need to be able to access a property via reflection, and, knowing that this property is an IEnumerable, append an object to it.
Something like this:
Object o;
MemberInfo m;
Array arr; // Except use IEnumerable, may have to take account of value/ref types
arr = (Array)((PropertyInfo)m).GetValue(o, null); }
List<o.GetType()> newArr = new List<o.GetType()>(); /* fails */
newArr.AddRange(arr);
newArr.Add(o);
((PropertyInfo)m).SetValue(o, newArr.ToArray(), null);
Can you help me where I'm going wrong :-)
Solution:
See accepted answer comments. Also (Get the actual type of a generic object parameter) is of help.
Once you have an IEnumerable type, use something like this to append to it:
public static IEnumerable<T> Append<T>(this IEnumerable<T> original, T next)
{
foreach (T item in original) yield return item;
yield return next;
}
public static IEnumerable<T> Append<T>(this IEnumerable<T> original, params T[] next)
{
foreach (T item in original) yield return item;
foreach (T item in next) yield return item;
}
public static IEnumerable<T> Append<T>(this IEnumerable<T> original, IEnumerable<T> next)
{
foreach (T item in original) yield return item;
foreach (T item in next) yield return item;
}
It sounds like you're essentially asking how to make a List<T> based on an unknown-at-compile-time type. For this you'll have to use a bit more reflection magic:
Type genericListType = typeof(List<>);
Type listType = genericListType.MakeGenericType(o.GetType());
object listInstance = Activator.CreateInstance(listType);
That would create a List<T> out of a runtime type.
But really, your code would be much simpler if you simply use ArrayList:
ArrayList list = new ArrayList(arr);
list.Add(o);
Array newArray = list.ToArray(o.GetType());