Подтвердить что ты не робот

Геттер и сеттер, исходящие из разных интерфейсов

Мне действительно нужно иметь что-то вроде этого:

interface IReadableVar
{
    object Value { get; }
}

interface IWritableVar
{
    object Value { set; }
}

interface IReadableWritableVar : IReadableVar, IWritableVar
{
}

Однако, когда я пытаюсь использовать IReadableWritableVar.Value, я получаю ошибки компиляции, если я явно не использовал базовый интерфейс, например здесь:

static void Main()
{
    IReadableWritableVar var = null;
    var t = var.Value;  // <-- CS0229: Ambiguity between 'IReadableVar.Value' and 'IWritableVar.Value'
    var.Value = null;   // <-- CS0229: Ambiguity between 'IReadableVar.Value' and 'IWritableVar.Value'

    var v = ((IReadableVar)var).Value;  // compiles fine
    ((IWritableVar)var).Value = null;   // compiles fine
}

Почему я получаю эти ошибки, хотя все должно быть ясно для компилятора? Есть ли способ исправить эту проблему, кроме кастинга (сотни мест в приложении)?

Обновление: было высказано предположение, что это обман Внедрение двух интерфейсов с свойствами "То же имя" , но это немного отличается, так как в другом случае наследования нет интерфейсы. Во всяком случае, проблема решена сейчас - см. Принятый ответ.

4b9b3361

Ответ 1

Возможное обходное решение может изменить ваш интерфейс IReadableWritableVar следующим образом:

interface IReadableWritableVar : IReadableVar, IWritableVar
{
    new object Value { get; set; }
}

Но сохраняйте в себе, что допустимая реализация должна быть:

class ReadableWritableVar : IReadableWritableVar
{
    public object Value
    {
        get { throw new NotImplementedException(); }
        set { throw new NotImplementedException(); }
    }

    object IWritableVar.Value
    {
        set { throw new NotImplementedException(); }
    }

    object IReadableVar.Value
    {
        get { throw new NotImplementedException(); }
    }
}

Более конкретный пример:

class ReadableWritableVar : IReadableWritableVar
{
    public object Value
    {
        get { return ((IReadableVar)this).Value; }
        set { ((IWritableVar)this).Value = value; }
    }

    object _val;

    object IWritableVar.Value { set { _val = value; } }

    object IReadableVar.Value => _val;
}

Или даже лучше:

class ReadableWritableVar : IReadableWritableVar
{
    public object Value { get; set; }

    object IWritableVar.Value { set { Value = value; } }

    object IReadableVar.Value => Value;
}

Ответ 2

Интересный вопрос. Я думаю, что методы расширения помогут в этом случае.

public static class Extension
{
    public static object GetValue(this IReadableVar v)
    {
        return v.Value;
    }

    public static void SetValue(this IWritableVar v, object value)
    {
        v.Value = value;
    }
}

Вам нужно изменить код, чтобы использовать его:

IReadableWritableVar variable = null;
var t = variable.GetValue();
variable.SetValue(null);

Метод расширения делает бросок для вас.

Ответ 3

Хорошо, эффективно Getter и Setter - это всего лишь два метода. Когда мы используем интерфейс IReadableWritableVar, существует два метода с одинаковым именем, унаследованным от базовых интерфейсов, и компилятор не знает, какой из этих двух он должен использовать, следовательно, двусмысленность.

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

Если мы реализуем этот элемент, ошибки не будет, поскольку компилятор будет использовать эту реализацию:

class ReadableWritableVar : IReadableWritableVar
{
    public object Value { get; set; }
}

var @var = new ReadableWritableVar();
var t = @var.Value;

Также вы можете использовать явную реализацию элементов интерфейса из ответа @Alessandro D'Andria, если требуется, чтобы вы использовали интерфейс, а не класс.

Ответ 4

с использованием абстрактного класса istead интерфейса решит вашу проблему.

public abstract class ReadableWritableVar : IReadableVar, IWritableVar
{
    public object Value { get; set; }       
}

Ответ 5

Одной из возможных альтернатив является использование явных (java style) методов get и set вместо свойства:

interface IReadableVar
{
    object GetValue();
}

interface IWritableVar
{
    void SetValue(object value);
}

interface IReadableWritableVar : IReadableVar, IWritableVar
{

}

Затем используется следующее:

static void Main(string[] args)
{
    IReadableWritableVar aVar = null;

    var t = aVar.GetValue();
    aVar.SetValue(null);
}