pinkie
pinkie

Reputation: 164

Can I define an Interface that IDictionary implements in C#?

Say I have a function that needs to operate on a instance of UsefulType, but must take an argument of type string. To do so, within the function I might look up some string -> OtherType mapping. I could make an interface that looks like

public interface IMapper {
    public UsefulType this[string key];
    public bool ContainsKey(string key);
}

and give my method the signature

public Task DoSomething(string thing, IMapper lookup)

It is clear to me that an IDictionary<string, UsefulType> logically implements IMapper, but of course the canonical definition doesn't include IMapper in its inheritance tree. Does C# provide any functionality such that a user could pass a Dictionary directly into this function without having to worry about implementing their own IMapper?

(In reality the signature for DoSomething would just contain a string - that's the constraint - and the IMapper would be owned by DoSomething's type. But I would still need the user to provide an IMapper for type instantiation, for example)

Upvotes: 0

Views: 90

Answers (1)

Sweeper
Sweeper

Reputation: 271735

No, you cannot retroactively make existing types implement/inherit other types, unless you are able to change their source code and recompile them.

Consider accepting an IReadOnlyDictionary instead. It isn't that different from your IMapper. It shouldn't be a lot more to implement. Count should be trivial if your mapping is finite. Keys and Values all return IEnumerables, so that gives you the ability to write iterators with yield return if it's inconvenient to return a collection. You can also write iterators in GetEnumerator (no need to implement your own IEnumerator), so IMO, it's not that much more work for finite mappings. You might not need these extra properties right now, but who knows, you might need them later!

If your mapping has infinitely many elements, then Count doesn't quite make sense. In that case, you can write a dictionary implementation of IMapper:

public class DictionaryMapper : IMapper
{
    private IReadOnlyDictionary<string, UsefulType> dict;
    public DictionaryMapper(IReadOnlyDictionary<string, UsefulType> dict)
    {
        this.dict = dict;
    }

    public UsefulType this[string key] => dict[key];

    public bool ContainsKey(string key) => dict.ContainsKey(key);
}

Now given a dictionary d, you can just do new DictionaryMapper(d) to get a IMapper implementation from that.

Upvotes: 2

Related Questions