Изменение свойства вводит в классе, который реализует интерфейс со свойством типа объекта

Я пишу TemplateEngine, который позволит мне использовать свою собственную разметку в основанных на тексте файлах. Я желаю добавить средства управления как плагины, поскольку приложение назревает. В настоящее время у меня есть структура как следующее:

interface IControl
    string Id
    object Value

class Label : IControl
    string Id
    string Value

class Repeater : IControl
    string Id
    List<IControl> Value

Теперь Вы будете видеть странную часть сразу же в классе Повторителя со свойством Value. Я надеялся, что, имея тип Значения, поскольку объект в интерфейсе позволит мне гибкость для расширения средств управления, поскольку я продвигаюсь. Компилятору не нравится это, и на серьезном основании я предполагаю.

Нижняя строка: я пытаюсь заставить все классы управления реализовывать тот же интерфейс, но иметь различные типы для свойства Value.

У кого-либо есть какие-либо предложения, как выполнить это?

Примечание: Не входите в предлагающие вещи как Механизм Представления Spark использования для шаблонной обработки. Существует причина, я создаю дополнительную работу для меня.

6
задан Flimzy 19 June 2018 в 11:11
поделиться

3 ответа

Обычно Repeater реализует что-то другое, например IItemsControl .

РЕДАКТИРОВАТЬ 1

(удалено для краткости)

РЕДАКТИРОВАТЬ 2

А, ладно, конечно, вы всегда можете использовать явную реализацию интерфейса:

interface IControl
{
    string Id { get; set; }
    object Value { get; set; }
}

class Label : IControl
{
    public string Id { get; set; }
    public string Value { get; set; }

    object IControl.Value
    {
        get { return this.Value; }
        set { this.Value = (string)value; }
    }
}

class Repeater : IControl
{
    public string Id { get; set; }
    public IList<IControl> Value { get; set; }

    object IControl.Value
    {
        get { return this.Value; }
        set { this.Value = (IList<IControl>)value; }
    }
}
9
ответ дан 8 December 2019 в 18:34
поделиться

] вы также можете использовать дженерики:

interface IControl<T> 
{
    string ID{get;set;}
    T Value{get;set;}
}

class SomeControl : IControl<string>
{
    public string ID{get;set}
    public string Value{get;set;}
}

class SomeOtherControl : IControl<int>
{
    public string ID{get;set}
    public int Value{get;set;}
}

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

Конечно, это не сработало бы, если бы у вас не было доступа к источнику IControl.

Edit: допущена опечатка. Исправлено

3
ответ дан 8 December 2019 в 18:34
поделиться

Нет, компилятор не позволяет полям с одним и тем же именем иметь разные типы данных, кроме тех, которые определены в интерфейсе в производных классах.

Свойства (поскольку в интерфейсе не допускаются поля) должны быть реализованы в производных классах, и они должны иметь тот же тип данных. Таким образом, вы, вероятно, не сможете сделать это со свойствами без явного объявления.

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

    interface IControl
    {
        object Value();
    }
    class A : IControl
    {
        string m_value = string.Empty;
        public object Value() { return m_value; }
    };
    class B : IControl
    {
        List<IControl> m_value = new List<IControl>();
        public object Value() { return m_value; }
    };
    ....
    object o = new B().Value();
    if (o is List<IControl>)
        MessageBox.Show("List");

[Обновление]
Будьте осторожны, если явно определяете тело характеристики. Одно имя для двух свойств было бы опасно, если реализация не будет выполнена тщательно.

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

        public IList<IControl> Value
        object IControl.Value

См. Этот пример:

    ...
    class Repeater : IControl
    {
        List<IControl> m_Value = new List<IControl>();
        public IList<IControl> Value
        {
            get { return this.m_Value; }
            set { this.m_Value = (IList<IControl>)value; }
        }
        object IControl.Value
        {
            get
            {
                return this.m_Value;
            }
            set
            {
                this.m_Value = new List<IControl>();
                this.m_Value.Add(new Label());
                this.m_Value.AddRange((List<IControl>)value);
            }
        }
    }
    ...
    Repeater b = new Repeater();
    IControl i = b;
    List<IControl> list = new List<IControl>();
    list.Add(new Repeater());
    i.Value = list;

Вы можете заметить, что контейнер списка в Repeater будет иметь разные значения при добавлении данных через IControl (из-за явного определения IContainer.Value).

1
ответ дан 8 December 2019 в 18:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: