拥有隐藏方法并在不同接口后面有不同的方法实现是一个坏主意吗?

时间:2011-01-13 16:37:44

标签: c# indexer explicit-interface

我有一个界面,目前扩展了IDictionary<> (以及扩展词典<>)的实现,但我希望有一个这个接口的实现,它不允许添加或删除条目(我希望允许更改现有条目)。我可以采用ReadOnlyCollection方法并抛出NotSupportedException,但这感觉有点不对。

相反,我想打破接口,所以我有一个用于访问器位,一个用于mutator位。这一切都没问题,但为了做到这一点,我最终得到了类似的东西(大多数方法都是为了简洁而删除):

public interface IAccessor<TKey, TValue>
    {
    TValue this [TKey key] { get; set; }
    }

然后我原来的界面变成了:

public interface IAttributeDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IAccessor<TKey, TValue>
    {
    new TValue this [TKey key] { get; set; }
    }

实现类定义为:

public class AttributeDictionary<TKey,TValue>: Dictionary<TKey, TValue>, IAttributeDictionary<TKey, TValue> 

我必须使索引器成为新的,以避免IDictionaryIAccessor中的索引器之间存在歧义。但真正的问题是,Dictionary上的setter索引器的行为是在字典中创建一个新条目。因为我希望IAccessor接口只允许修改条目而不创建条目,我应该在AttributeDictionary的实现中做什么?我应该有一个IAccessor索引器方法的显式实现,它首先检查给定的密钥是否在字典中,如果没有,则抛出异常,或者有2个具有不同行为的索引器是个坏主意?或者我应该放弃IAccessor界面中的索引器,而只是使用GetValueSetValue方法,以避免混淆?

1 个答案:

答案 0 :(得分:1)

问题在于你仍在努力实现IDictionary - 我认为你不应该在你的AttributeDictionary上实现该界面(因为你并不真正支持界面强制要求的全部功能)。但是,如果您必须支持它,因为您需要将AttributeDictionary的实例发送到采用IDictionary的方法,并且IDictionary的实现链中没有更高的接口,您可以使用,我认为下一个最好的事情就是单独实现IDictionary并抛出索引器的setter。

我觉得你现在正在尝试的方法只会导致你在不知道它的情况下调用错误索引器的细微错误,特别是在通过接口本身处理类的实例时。

编辑:Sam对此答案的第一次评论后:

这样的方法怎么样:

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

public interface IAttributeDictionary<K,V> : IAccessor<K,V>, IDictionary<K,V> {
    // This interface just composes the other two.
}

public class Test<K,V> : IAttributeDictionary<K,V> {
    // This will implement the indexer for both IAccessor and IDictionary.
    // But when the object is accessed as an IAccessor the setter is not available.
    public V this[K key] {
        get { Console.WriteLine("getter"); return default(V); }
        set { Console.WriteLine("setter"); }
    }

    // ...the rest of IDictionary goes here...
}

class Program {
    static void Main (string[] args) {
        // Note that test can be accessed as any of the appropriate types,
        // and the same getter is called.
        Test<string,int> test = new Test<string, int>();
        int a = test["a"];
        int b = ((IDictionary<string, int>)test)["b"];
        int c = ((IAccessor<string, int>)test)["c"];
    }
}

编辑2.0: 在以下评论中的所有讨论之后,我想我可能最终会理解这个问题,所以......

我认为IAccessor真的不应该使用索引器,因为(在我看来)你想要的行为是非常不寻常和意外的。我会在GetValueForKeyChangeValueForKeyIAccessor提供您想要的行为,并在具体实现类中实现IDictionary的索引器。如果由于任何原因这是不可接受的,我建议然后使用显式接口实现在实现类中实现IAccessor及其索引器 - 在这两种情况下,我都不认为IAttributeDictionary中的新声明是必要的。