views:

487

answers:

2

Note: This is similar, but not quite the same as this other question

I've implemented an IBusinessCollection interface. It dervies from both ICollection<T>, and the old-busted non-generic ICollection. I'd prefer to just dump the old busted ICollection, but I'm using WPF databinding with a CollectionView which wants me to implement the old-busted non-generic IList :-(

Anyway, the interfaces look like this:

public interface IBusinessCollection<T> : ICollection<T>, ICollection
{ }

public interface ICollection<T>
{ int Count { get; } }

public interface ICollection
{ int Count { get; } }

Due to using Dependency Injection, I'm passing around objects of type IBusinessCollection<T> using their interfaces, not by concrete types, so I have something like this:

internal class AnonymousCollection : IBusinessCollection<string>
{ 
    public int Count { get { return 5; } }
}

public class Factory
{
    public static IBusinessCollection<string> Get()
    { return new AnonymousCollection(); }
}

When I try and call this code, I get an error, as follows:

var counter = Factory.Get();
counter.Count; // Won't compile
// Ambiguity between 'ICollection<string>.Count' and 'ICollection.Count'

There are 3 ways to make this compile, but all of them are ugly.

  1. Cast the class to it's concrete implementation (which I may not know)

  2. Cast the class explicitly to ICollection

  3. Cast the class explicitly to ICollection<T>

Is there a fourth option which doesn't require me to cast things at all? I can make whatever changes I need to IBusinessCollection<T>

A: 
ICollection<string> counter = Factory.Get();
counter.Count; // No longer ambiguous
Matthew Scharley
I don't think this actually solves the problem. In my sample code, I get the ambiguity error with `var` or the explicit `IBusinessCollection<string>` type.
bobbymcr
The question requested a fourth option. He already knew about this possibility.
John Fisher
I still get the ambiguity err.
Corbin March
I've juggled this around in edits, and finally settled on `ICollection<string>` because I don't know if using `IBusinessCollection<string>` actually resolves the conflict or not (probably not). If you actually need an `IBusinessCollection<string>` type for your variable, then you may need to cast.
Matthew Scharley
@John: This is *not* a cast, it's not even a conversion, it's a simple assignment to a lower level type. It also avoids using the concrete type, so I don't see how this isn't a different solution. @bobby: You're right, see my last comment and edits fixing up the misleading info.
Matthew Scharley
@Matthew: In #1, he clearly indicates that he may not know the right type to use. So, he wouldn't be able to specify "ICollection<string>" as the variable type.
John Fisher
@John: of course he can. He knows he's getting an `IBusinessObject<string>`. This interface implements `ICollection<string>`. Contrary to popular believe `var` is **not** variant! It's a static type that is in this case being resolved at compile time to `IBusinessCollection<string>`, which has two properties defined in two seperate subinterfaces that have the same name. Using one or the other if possible removes the ambiguity.
Matthew Scharley
I don't want to cast it or have to explicitly state the type. I just want to use var and have clean code. As far as that goes, ICollection<string> counter is the same as var counter = (ICollection<string>), and doesn't solve the issue
Orion Edwards
+5  A: 

This appears to solve the issues in my quick tests.

public interface IBusinessCollection<T> : ICollection<T>, ICollection
{
    new int Count { get;  }
}
John Fisher
This works perfectly. Thanks!
Orion Edwards
PS. Didn't know you could do 'new' in interfaces. That's nice :-)
Orion Edwards