简体   繁体   中英

C# Generics cant pass a list

Im pretty new to generics and am trying to build myself a helper method for creating 2 dimensional object array as below.

public static class CarouselHelper<T> where T : new()
{
    public static IEnumerable<T[,]> BuildCarousel(T data, int rows, int columns)
    {
        T [,] carousel = new T[rows, columns];
        List<T[,]> slides = new List<T[,]>();

        int rowCount = 0, columnCount = 0, itemCount = 1;


        foreach (var item in data)
        {
            if (itemCount % 2 == 0)
            {
                rowCount = 0;
                columnCount = columnCount++;
            }

            carousel[rowCount, columnCount] = item;


            if (rowCount == rows && columnCount == columns)
            {
                slides.Add(carousel);
                carousel = new T[rows, columns];
            }

            itemCount = itemCount++;
        }

        return null;
    }
}

Im calling the method as follows

var bob = Common.CarouselHelper<List<VideoListModel>>.BuildCarousel(ds, 2, 4);

I get the following error when I run and not sure where to go from here?

foreach statement cannot operate on variables of type 'T' because 'T' does not contain a public definition for 'GetEnumerator'

Your error message is quite still. You're trying to iterate over T instance, without being sure it's possible.

It's hard to tell how to fix this without knowledge what is ds type, but you should probably change your method declaration to be:

public static IEnumerable<T[,]> BuildCarousel(IEnumerable<T> data, int rows, int columns)

btw. You never increment rowCount , so it's always set to 0 . Are you sure the algorithm is correct?

Basically you cant use any methods on your generic type that might not exist, its all still statically typed,

ie you have

foreach (var item in data)

and data is type T, and so T must be IEnumerable, and so you need to explicitly constrain the generic type, ie

public static class CarouselHelper<T> where T : new(), IEnumerable

see http://msdn.microsoft.com/en-us/library/d5x73970.aspx

The fundamental problem is that T is your fundamental data type. It's not enumerable: the IEnumerable<T> needs to be in the method prototype's declaration of its data argument.

But it seems awfully...complicated. Why don't you do something simpler, like this?

public static class CarouselHelper<T>
{
  public static IEnumerable<T[,]> BuildCarousel( IEnumerable<T> data, int rows, int cols )
  {
    List<T[,]> slides = new List<T[,]>();
    using ( IEnumerator<T> enumerator = data.GetEnumerator() )
    {
      bool moved = true ;
      do
      {
        T [,] carousel = new T[ rows, cols ] ;
        for ( int i = 0 ; i < rows ; ++i )
        {
          for ( int j = 0 ; j < cols ; ++j )
          {
            moved = enumerator.MoveNext() ;
            T currentCell = moved ? enumerator.Current : default(T) ;
            carousel[i,j] = currentCell ;
          }
        }
        slides.Add(carousel) ;
      } while ( moved ) ;
    }
    return slides ;
  }
}

The above builds the 2d arrays out in row-major order; if you want them built in column-major order, just swap the nested for loops at the core:

T [,] carousel = new T[ rows, cols ] ;
for ( int j = 0 ; j < cols ; ++j )
{
  for ( int i = 0 ; i < rows ; ++i )
  {
    moved = enumerator.MoveNext() ;
    T currentCell = moved ? enumerator.Current : default(T) ;
    carousel[i,j] = currentCell ;
  }
}
slides.Add(carousel) ;

Even better, since you're returning IEnumerable<T> ... make the evaluation lazy:

public static class CarouselHelper<T>
{
  public static IEnumerable<T[,]> BuildCarousel( IEnumerable<T> data, int rows, int cols )
  {
    using ( IEnumerator<T> enumerator = data.GetEnumerator() )
    {
      bool moved = true ;
      do
      {
        T [,] carousel = new T[ rows, cols ] ;
        for ( int i = 0 ; i < rows ; ++i )
        {
          for ( int j = 0 ; j < cols ; ++j )
          {
            moved = enumerator.MoveNext() ;
            T currentCell = moved ? enumerator.Current : default(T) ;
            carousel[i,j] = currentCell ;
          }
        }
        yield return carousel ;
      } while ( moved ) ;
    }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM