Chris Pfohl
Chris Pfohl

Reputation: 19064

C# Convert to Interface

Is it possible to define how to cast a built in object to an interface in C#? Interfaces can't define operators. I have a very simple interface that allow index access, but not mutation:

public interface ILookup<K, V>
{
    V this[K key] { get; }
}

I'd like to be able to cast a Dictionary<K, V> to an ILookup<K, V>. In my ideal dream world this would look like:

//INVALID C#
public interface ILookup<K, V>
{
    static implicit operator ILookup<K, V>(Dictionary<K, V> dict)
    {
         //Mystery voodoo like code. Basically asserting "this is how dict
         //implements ILookup
    }
    V this[K key] { get; }
}

What I've worked out as a workaround is this:

public class LookupWrapper<K, V> : ILookup<K, V>
{
    private LookupWrapper() { }

    public static implicit operator LookupWrapper<K, V>(Dictionary<K, V> dict)
    {
        return new LookupWrapper<K, V> { dict = dict };
    }

    private IDictionary<K, V> dict;
    public V this[K key] { get { return dict[key]; } }
}

This works and means I can now directly cast from Dictionary to ILookup, but boy does it feel convoluted...

Is there a better way to force a conversion to an interface?

Upvotes: 2

Views: 4895

Answers (5)

Hounshell
Hounshell

Reputation: 5459

It's a pretty egregious bastardization of the language, but there is a way. I assume your basically trying to apply an interface to a class that already has the signatures you want, you just want a subset (like in your example).

You can use a TransparentProxy/RealProxy pair to create a class at runtime that implements any interface (or MarshalByRef object). There's an abstract method you need to implement to handle the call, but with a little elbow grease you can make this generic enough to be able to handle this kind of situation.

We ran into a similar problem with a library that was very badly wrapped (we had to use reflection to make every method call). So rather than write out a ton of custom reflection code, we wrote the generic case and then wrote a bunch of interfaces that matched the signatures. Then we just used the interfaces directly. We even wrapped/unwrapped objects automatically so we could just make our interface methods return other interfaces and it would all just work.

There's a super-long writeup of the methodology and an implementation at http://blog.paulhounshell.com/?s=Duck

Upvotes: 0

John Alexiou
John Alexiou

Reputation: 29244

The best you can do is use Extension methods and a wrapper class...

public interface ILookup<K, V>
{
    V this[K key] { get; }
}

public class DictWrapper<K, V> : ILookup<K, V>
{
    Dictionary<K, V> dictionary;

    public DictWrapper(Dictionary<K, V> dictionary)
    {
        this.dictionary = dictionary;
    }

    public V this[K key]
    {
        get { return dictionary[key]; }
    }

    protected internal Dictionary<K, V> InnerDictionary { get { return dictionary; } }
}

public static class Extensions
{
    public static ILookup<K, V> ToLookup<K, V>(this Dictionary<K, V> dictionary)
    {
        return new DictWrapper<K, V>(dictionary);
    }
}

class Program
{
    static void Main(string[] args)
    {
        Dictionary<string, int> data = new Dictionary<string, int>();

        data.Add("Office", 100);
        data.Add("Walls", 101);
        data.Add("Stair", 30);

        ILookup<string, int> look = data.ToLookup();
    }
}

Upvotes: 0

Chris Pfohl
Chris Pfohl

Reputation: 19064

Thanks to @MBabcock's comment I realized I was thinking about this wrong. I promoted the interface to a full on class as follows:

public class Lookup<K, V>
{
    private readonly Func<K, V> lookup;
    protected Lookup(Func<K, V> lookup)
    {
        this.lookup = lookup;
    }

    public static implicit operator Lookup<K, V>(Dictionary<K, V> dict)
    {
        return new Lookup<K, V>(k => dict[k]);
    }

    public V this[K key]
    {
        get { return lookup(key); }
    }
}

Any further conversions I need like this I can simply add an implicit operator

Upvotes: 0

Daniel Gabriel
Daniel Gabriel

Reputation: 3985

If you have any control over the Dictionary, you can subclass it and override this[] in your subclass. Then use your new dictionary instead of the .NET one.

Upvotes: 0

Jon
Jon

Reputation: 437376

Since interfaces cannot include actual code, it follows that you need some class which will "host" the code for the cast. This can either be a class that implements the interface (obviously), or otherwise it needs to be a wrapper class like the one you have¹. There is no third option.

¹The way in which you "invoke" the cast can differ (e.g. you can hide the construction of a LookupWrapper behind an extension method), but this does not change things.

Upvotes: 2

Related Questions