Это плохая идея иметь методы скрытия и иметь разные реализации методов за разными интерфейсами? - PullRequest
0 голосов
/ 13 января 2011

У меня есть интерфейс, который в настоящее время расширяет IDictionary <> (и реализация, которая расширяет словарь <>), но я хочу иметь реализацию этого интерфейса, которая не позволяет добавлять или удалять записи (я хочу разрешить существующиезаписи должны быть изменены, хотя).Я мог бы просто воспользоваться подходом ReadOnlyCollection и выдать исключение NotSupportedException, но это выглядит немного неправильно.

Вместо этого я хотел бы разбить интерфейсы, чтобы у меня был один для битов доступа и один для битов мутатора.Это все в порядке, за исключением того, что для этого у меня получилось что-то вроде этого (большинство методов убрано для краткости):

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> 

Мне пришлось сделать индексатор новым, чтобы избежать неоднозначностей между индексаторами в IDictionary и IAccessor.реальная проблема заключается в том, что поведение индексатора установщика на Dictionary заключается в создании новой записи в словаре.Поскольку я хочу, чтобы интерфейс IAccessor позволял изменять и не создавать только записи, что я должен делать при реализации AttributeDictionary?у меня должна быть явная реализация метода индексатора IAccessor, который сначала проверяет, находится ли данный ключ в словаре, и выдает исключение, если нет, или было бы плохой идеей иметь 2 индексатора с другим поведением?Или я должен отказаться от индексатора в интерфейсе IAccessor и просто использовать вместо него методы GetValue и SetValue и избежать путаницы?

1 Ответ

1 голос
/ 13 января 2011

Меня поразила проблема в том, что вы все еще пытаетесь реализовать IDictionary - я думаю, вам не следует реализовывать этот интерфейс на вашем AttributeDictionary (потому что вы на самом деле не поддерживаете полную функциональность, предписанную интерфейс). Однако, если вам необходимо его поддержать, потому что вам нужно отправлять экземпляры AttributeDictionary методам, которые принимают IDictionary, и нет никаких интерфейсов выше в цепочке реализации IDictionary, которую вы можете использовать, я думаю, что следующий лучший дело в том, чтобы просто реализовать IDictionary в одиночку и добавить установщик индексатора.

Мне кажется, что подход, который вы сейчас используете, просто приведет к незначительным ошибкам, когда вы вызываете неправильный индексатор, даже не подозревая об этом, особенно при работе с экземплярами класса через сами интерфейсы.

РЕДАКТИРОВАТЬ: После первого комментария Сэма к этому ответу:

А как насчет такого подхода:

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 на самом деле не должен использовать индексатор, поскольку (на мой взгляд) поведение, которое вы хотите получить от него, довольно необычно и неожиданно. Вместо этого я хотел бы иметь GetValueForKey и ChangeValueForKey для IAccessor, которые могут обеспечить требуемое поведение, и реализовать индексатор из IDictionary в конкретном классе реализации. Если по какой-либо причине это неприемлемо, я бы предложил затем использовать явную реализацию интерфейса для реализации IAccessor и его индексатора в классе реализации - в обоих случаях я не думаю, что новое объявление в IAttributeDictionary необходимо.

...