views:

825

answers:

5

I've got a collection that implements an interface that extends both IList<T> and List.

public Interface IMySpecialCollection : IList<MyObject>, IList { ... }

That means I have two versions of the indexer.

I wish the generic implementation to be used, so I implement that one normally:

public MyObject this[int index] { .... }

I only need the IList version for serialization, so I implement it explicitly, to keep it hidden:

object IList.this[int index] { ... }

However, in my unit tests, the following

MyObject foo = target[0];

results in a compiler error

The call is ambiguous between the following methods or properties

I'm a bit surprised at this; I believe I've done it before and it works fine. What am I missing here? How can I get IList<T> and IList to coexist within the same interface?

Edit IList<T> does not implement IList, and I must implement IList for serialization. I'm not interested in workarounds, I want to know what I'm missing.

Edit again: I've had to drop IList from the interface and move it on my class. I don't want to do this, as classes that implement the interface are eventually going to be serialized to Xaml, which requires collections to implement IDictionary or IList...

A: 

List<T> implies IList, so it's a bad idea to use both in the same class.

Joel Coehoorn
IList<T> does not implement IList. And I need to implement IList for serialization purposes.
Will
+1  A: 

Unfortunately you can't declare two indexers with the same parameter list. The following paragraph is taken from here C# Programming Guide - Using Indexers "Remarks" section:

The signature of an indexer consists of the number and types of its formal parameters. It does not include the indexer type or the names of the formal parameters. If you declare more than one indexer in the same class, they must have different signatures.

You will have to declare a different set of parameters if you wish to use the second indexer.

Aydsman
You can't have 2 indexers 'this', but you can have a 'string IDataErrorInfo.this' and a 'T IList<T>.this'. You'll have to cast the object before accessing the indexer, but it works.
Jarrett Meyer
A: 

Change your generic implementation to...

T IList<T>.this[int index] { get; set; }

This explicitly says which 'this' is which.

Jarrett Meyer
with both implemented explicitly, you need to cast the list to use either one, which is not what he wants. he wants to default to the generic one and hide the non-generic one.
Lucas
+1  A: 

You can't do this with

public interface IMySpecialCollection : IList<MyObject>, IList { ... }

But you can do what you want with a class, you will need to make the implementations for one of the interfaces explicit. In my example I made IList explicit.

public class MySpecialCollection : IList<MyObject>, IList { ... }

IList<object> myspecialcollection = new MySpecialCollection(); IList list = (IList)myspecialcollection;

Have you considered having IMySpecialCollection implement ISerializable for serialization? Supporting multiple collection types seems a bit wrong to me. You may also want to look at casting yout IList to IEnumerable for serialization since IList just wraps IEnumerable and ICollection.

Darryl Braaten
Its Xaml serialization. XamlReader doesn't care about ISerializable, it just cares that you implement IList or IDictionary (and, if anybody goes looking through Reflector, IAddChild is going to be deprecated and the serializer ignores it).
Will
+1 for noticing that this error occurs when using an interface but not a class. 0 for ISerializable + Xaml :P
Lucas
A: 

This is a dupe of my question here

To summarise, if you do this, it solves the problem:

public Interface IMySpecialCollection : IList<MyObject>, IList
{
    new MyObject this[int index];
    ... 
}
Orion Edwards