I am trying to use this extension method which allows to get row index while iterating with foreach. This method belongs to @Jon Skeet . From its extensive library of classes, I'm interested in this SmartEnumerable
.
I have my own class library, called MetodosExtension
in which I have several things inside, among them a folder called "Classes" and inside this folder my class Funciones.cs
. I want to add Jon's method to my class.
/// <summary>
/// Static class to make creation easier. If possible though, use the extension
/// method in SmartEnumerableExt.
/// </summary>
public static class SmartEnumerable
{
/// <summary>
/// Extension method to make life easier.
/// </summary>
/// <typeparam name="T">Type of enumerable</typeparam>
/// <param name="source">Source enumerable</param>
/// <returns>A new SmartEnumerable of the appropriate type</returns>
public static SmartEnumerable<T> Create<T>(IEnumerable<T> source)
{
return new SmartEnumerable<T>(source);
}
/// <summary>
/// Extension method to make life easier.
/// </summary>
/// <typeparam name="T">Type of enumerable</typeparam>
/// <param name="source">Source enumerable</param>
/// <returns>A new SmartEnumerable of the appropriate type</returns>
public static SmartEnumerable<T> AsSmartEnumerable<T>(this IEnumerable<T> source)
{
return new SmartEnumerable<T>(source);
}
}
/// <summary>
/// Type chaining an IEnumerable<T> to allow the iterating code
/// to detect the first and last entries simply.
/// </summary>
/// <typeparam name="T">Type to iterate over</typeparam>
public class SmartEnumerable<T> : IEnumerable<SmartEnumerable<T>.Entry>
{
/// <summary>
/// Enumerable we proxy to
/// </summary>
readonly IEnumerable<T> enumerable;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="enumerable">Collection to enumerate. Must not be null.</param>
public SmartEnumerable(IEnumerable<T> enumerable)
{
if (enumerable==null)
{
throw new ArgumentNullException ("enumerable");
}
this.enumerable = enumerable;
}
/// <summary>
/// Returns an enumeration of Entry objects, each of which knows
/// whether it is the first/last of the enumeration, as well as the
/// current value.
/// </summary>
public IEnumerator<Entry> GetEnumerator()
{
using (IEnumerator<T> enumerator = enumerable.GetEnumerator())
{
if (!enumerator.MoveNext())
{
yield break;
}
bool isFirst = true;
bool isLast = false;
int index=0;
while (!isLast)
{
T current = enumerator.Current;
isLast = !enumerator.MoveNext();
yield return new Entry(isFirst, isLast, current, index++);
isFirst = false;
}
}
}
/// <summary>
/// Non-generic form of GetEnumerator.
/// </summary>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// Represents each entry returned within a collection,
/// containing the value and whether it is the first and/or
/// the last entry in the collection's. enumeration
/// </summary>
public class Entry
{
readonly bool isFirst;
readonly bool isLast;
readonly T value;
readonly int index;
internal Entry(bool isFirst, bool isLast, T value, int index)
{
this.isFirst = isFirst;
this.isLast = isLast;
this.value = value;
this.index = index;
}
/// <summary>
/// The value of the entry.
/// </summary>
public T Value { get { return value; } }
/// <summary>
/// Whether or not this entry is first in the collection's enumeration.
/// </summary>
public bool IsFirst { get { return isFirst; } }
/// <summary>
/// Whether or not this entry is last in the collection's enumeration.
/// </summary>
public bool IsLast { get { return isLast; } }
/// <summary>
/// The 0-based index of this entry (i.e. how many entries have been returned before this one)
/// </summary>
public int Index { get { return index; } }
}
}
I have already recompiled my Library, I have added the DLL in the project where I want to invoke the method and also the using
corresponding one.
I want to use it like this:
using System;
//.....
using MetodosExtension.Clases;
public class Prueba
{
public void Prueba()
{
///Asumiendo que mi "table" esta lleno....
foreach (var item in table.Rows.AsSmartEnumerable())
{
int index = item.Index;
DataRow value = item.Value;
bool isFirst = item.IsFirst;
bool isLast = item.IsLast;
}
}
}
But the compiler shows me:
"DataRowCollection" does not contain a definition for "AsSmartEnumerable" and no accessible "AsSmartEnumerable" extension method is found that accepts a first argument of type "DataRowCollection" (are you missing a using directive or an assembly reference?)
As I already mentioned I have added the assembly and the using
.
Environment: Visual Studio 2017, .NetFrameWork 4.5.2
What am I doing wrong?
- You can see the usage page for more details.
- If you want to take a look at the complete MiscUtil Library
If you notice, in the class
SmartEnumerable
, you have the generic and extension methodAsSmartEnumerable<T>
which extends the interface .this
IEnumerable<T>
This means that only those Classes that implement the interface
IEnumerable<T>
will be able to use the extension methodAsSmartEnumerable<T>
.In your case, you are recurring in the Foreach the rows (Rows) of a table that are of the type
DataRowCollection
(as indicated by the error). And what happens is that it doesDataRowCollection
NOT implement the interfaceIEnumerable<T>
.For the example to work for you, you should use a generic list
List<T>
, which DOES implement the interfaceIEnumerable<T>
.An example would be the following:
After further investigation I have found a solution for this, basically this should work with any
IEnumerable<T>
, what happens in this case is as Rafael Acosta mentions in his answer, it does not implement the genericDataRowCollection
interface .IEnumerable<T>
DataTable.Rows
it only implements the non-generic interface . What derives fromInternalDataCollectionBase
. That implements the non-generic interfaceICollection
, which means that the compiler cannot infer the type ofrow
beyond justobject
.So to achieve this goal with a
DataTable.Rows
you must use LINQ to callCast
and then callAsSmartEnumerable
on the result, as follows:This is not specific to
DataTable
: whenever you have something that just implementsIEnumerable
instead ofIEnumerable<T>
(and doesn't have a more specific methodGetEnumerator
for the compiler to use), the inferred iteration element type is justobject
.