21

When we declare a parameter as ICollection and instantiated the object as List, why we can't retrive the indexes? i.e.

ICollection<ProductDTO> Products = new List<ProductDTO>();
Products.Add(new ProductDTO(1,"Pen"));
Products.Add(new ProductDTO(2,"Notebook"));

Then, this will not work:

ProductDTO product = (ProductDTO)Products[0];

What is the bit I am missing?
[Yes, we can use List as declaration an it can work, but I don't want to declare as list, like:

List<ProductDTO> Products = new List<ProductDTO>();

]

demokritos
  • 1,416
  • 2
  • 12
  • 34

7 Answers7

39

Using LINQ, you can do this:

ProductDTO product = (ProductDTO)Products.ElementAt(0);
jeremcc
  • 8,633
  • 11
  • 45
  • 55
29

The ICollection interface doesn't declare an indexer, so you can't use indexing to fetch elements through a reference of that type.

You could perhaps try IList, which adds some more functionality, while still being abstract. Of course, this may impact other design decisions so I would look at this carefully.

Chris W. Rea
  • 5,430
  • 41
  • 58
  • When you say design decision. What do you mean? What is best using IList or ICollection? –  Feb 06 '15 at 11:00
  • 2
    @Inanikian There is no "best"; it depends on context. If you must use methods in IList, say if you require indexing/ordering, then IList may be the best interface type to require. If, on the other hand, you only care to count, add, remove, and enumerate items, but never by index, and don't want to impose a requirement of additional functionality on a class to have an indexer and all the other functionality implied by IList that you wouldn't use anyway, then it may be better to require only what you need, e.g., ICollection (or even IEnumerable, if you aren't modifying anything). – Chris W. Rea Feb 06 '15 at 15:46
7

ICollection does not define an indexer.

ICollection Non-Generic

ICollection Generic

ChaosPandion
  • 77,506
  • 18
  • 119
  • 157
5

Then this will work:

ProductDTO product = ((IList<ProductDTO>)Products)[0];

The reason is that the compiler evaluates the lvalue, that is the variable on the left side of '=', to find out which methods and properties it knows it can access at compile-time. This is known as static typing, and ensures that an object member can be accessed directly at runtime by statically knowing that the member is always reachable.

Cecil Has a Name
  • 4,962
  • 1
  • 29
  • 31
  • 1
    This eliminates the benefit of working with the abstraction provided by an interface: if Products is later changed to be something other than List, the code above is broken because it makes an assumption about underlying type when performing the cast. – Chris W. Rea Dec 09 '09 at 19:01
  • 1
    Yes, but it fixes the single statement the OP complained about. – Cecil Has a Name Dec 09 '09 at 19:39
  • 2
    You and I have different definitions of the word **fixes**! ;-) – Chris W. Rea Dec 09 '09 at 21:04
  • 1
    You need to read my comment one more time: It changes a *single* statement. I never said I fixed the *cause of the problem*. You can't always call it a spade for its looks, a so-called *fix* in the programming world. – Cecil Has a Name Dec 09 '09 at 22:13
3

The basic problem is that ICollection doesn't define an index. For the List this is done by the implementation of IList.

Try this:

IList<ProductDTO> Products = new List<ProductDTO>(); 

Alternatly, you can keep using ICollection and convert to an array when you need to access the elements by the index:

ICollection<ProductDTO> Products = new List<ProductDTO>();        
ProductDTO z = Products.ToArray()[0];
Stephen M. Redd
  • 5,378
  • 1
  • 24
  • 32
3

Using Linq, you can access an element in an ICollection<> at a specific index like this:

myICollection.AsEnumerable().ElementAt(myIndex);
NoRelect
  • 598
  • 4
  • 20
0

You can also use extension methods to convert it to (list, array) of ProductDTO

ICollection<ProductDTO> Products = new List<ProductDTO>();
var productsList = Products.ToList();

Then you can use it like that:

productsList[index]
Qais Bsharat
  • 146
  • 3
  • 12