2

是否可以定义如何将内置对象转换为 C# 中的接口?接口不能定义操作符。我有一个非常简单的界面,允许索引访问,但不允许突变:

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

我希望能够将 aDictionary<K, V>转换为ILookup<K, V>. 在我理想的梦想世界中,这看起来像:

//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; }
}

我制定的解决方法是这样的:

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]; } }
}

这行得通,意味着我现在可以直接从 Dictionary 转换为 ILookup,但是男孩感觉很复杂......

有没有更好的方法来强制转换为接口?

4

5 回答 5

2

由于接口不能包含实际代码,因此您需要一些将“托管”转换代码的类。这可以是一个实现接口的类(显然),或者它需要是一个包装类,就像你所拥有的一样¹。没有第三种选择。

¹您“调用”演员表的方式可能会有所不同(例如,您可以隐藏LookupWrapper扩展方法后面的构造),但这不会改变事情。

于 2011-12-15T01:14:49.247 回答
0

如果您对字典有任何控制权,则可以将其子类化并this[]在子类中覆盖。然后使用您的新字典而不是 .NET 字典。

于 2011-12-15T01:22:13.100 回答
0

感谢@MBabcock 的评论,我意识到我想错了。我将接口提升为一个完整的类,如下所示:

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); }
    }
}

我需要这样的任何进一步转换,我可以简单地添加一个隐式运算符

于 2011-12-15T01:25:55.520 回答
0

你能做的最好的就是使用扩展方法和一个包装类......

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();
    }
}
于 2011-12-15T01:40:29.467 回答
0

这是一种非常令人震惊的语言混蛋,但有一种方法。我假设您基本上尝试将接口应用于已经具有所需签名的类,您只需要一个子集(如您的示例中所示)。

您可以使用透明代理/真实代理对在运行时创建一个实现任何接口(或 MarshalByRef 对象)的类。您需要实现一个抽象方法来处理调用,但只需稍加努力,您就可以使这个方法足够通用,以便能够处理这种情况。

我们在一个包装非常糟糕的库中遇到了类似的问题(我们必须使用反射来进行每个方法调用)。因此,我们没有编写大量自定义反射代码,而是编写了通用案例,然后编写了一堆与签名匹配的接口。然后我们就直接使用接口了。我们甚至自动包装/解包对象,因此我们可以让我们的接口方法返回其他接口,这一切都可以正常工作。

在http://blog.paulhounshell.com/?s=Duck上有一个超长的方法论和实现

于 2011-12-15T01:48:07.383 回答