开发者

Avoiding ambiguous invocation error with generic types

开发者 https://www.devze.com 2023-02-24 21:02 出处:网络
I have a two way dictionary class that I am making to allow me to do a fast lookup in either direction.

I have a two way dictionary class that I am making to allow me to do a fast lookup in either direction.

My class looks (partially) like this:

public class DoubleDictionary<A,B>
{
    private Dictionary<A, B> _forward;
    private Dictionary<B, A> _backward;

    public A this[B b]
    {
        get { return _backward[b]; }
        set { _backward[b] = value; }
    }

    public B this[A a]
    {
        get { return _forward[a]; }
        set { _forward[a] = value; }
    }
}

I am using the array indexing operator in this example, but just about every method has two generic versions. It works great except in the case where A == B.

If I do

var foo = new DoubleDictionary<int, int>();
int x = foo[3];

It won't even compile because of an ambiguous indexer.

I understand why the compiler has a problem with this, and I agree that it should probably not be legal.

Lets assume I actually have a valid use case for wanting a DoubleDictionary<int,int>, and I arbitrarily choose that the array index should access the forward dictionary.

The solution I have arrived at to work around all of this is to abandon the slick indexing syntax for uniquely named methods for each direction. This makes it much less magic, and much less fun.

Is there any way to give the compiler hints to resolve the ambiguity without having to resort to uniquely named methods? I really like the idea of doing this with overloads and would like to keep it that way. I would prefer to do that in the class so the caller doesn't have to worry about it, but I imagine the caller will have to do some kind of reflection magic to make it work.

If its not possible I would be fine with the restraint that A cannot be the same as B. Is there any way to 开发者_Python百科codify that, so that a declaration of DoubleDictionary<int,int> would not compile? I could throw an exception in the constructor, but it would be nice if it was caught at compile time.


Well, having the two indexers, if it were allowed, would be a monumentally bad design.

Having this dictionary:

var foo = new DoubleDictionary<int, int>();
foo.Add(3, 4);
foo.Add(2, 3);

and then doing:

foo[3]

would you expect to get 2? or 4? and why?

Better make the API clear.


You can always keep the indexers, but add the named methods as an auxiliary API - perhaps even via extension methods so you can bring them into play by adding a using directive...


There isn't any way to resolve the ambiguity as-is, given that it's an indexer that doesn't allow you to specify arguments and that the only way to relate type parameters in generic constraints is by inheritance.

I think that a good compromise would be to use the indexer for forward look-ups and something like a GetKeyForValue(B value) method for backward look-ups.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号