C # - сложное присваивание переменной - PullRequest
2 голосов
/ 14 июля 2011

у меня есть класс Row.Этот класс должен иметь свойство Content.В настоящее время содержимое имеет тип: List<IRowContent>

(IRowContent - это интерфейс)

Другие классы Column и TextContent, ImageContent реализуют интерфейс IRowContent.

Теперь я могу добавить несколько столбцов в список или реальный «контент» (текст или изображение).

Но вы также можете добавить столбцы и текст / изображение.Но если строка содержит текст / изображение, она не должна содержать другой элемент.

Как мне спроектировать мою классовую структуру для поддержки этого?

Редактировать : некоторые дополнительные сведения: Я хочу создать макет с помощью « плавных интерфейсов » http://en.wikipedia.org/wiki/Fluent_interface

И моя идея состоит в том, чтобы предотвратить неправильное использование intellisense VisualStudio.

Вот мои классы:Макет имеет список столбцов.

class Layout
   {
      //Attributes
      public Color Background { get; set; }
      public List<Column> Columns { get; set; }
      public uint Margin { get; set; }

      public Layout AddColumn(Column c)
      {
         return null;
      }

      public Layout SetColumnList(List<Column> c)
      {
         return null;
      }
   }

Столбец содержит список содержимого (IColumnContent).Сам столбец из IRowContent.

class Column : IRowContent
   {
      public List<IColumnContent> Content { get; private set; }

      public Column AddToContent(IColumnContent obj)
      {
         return null;
      }

      public Column SetContent(List<IColumnContent> objs)
      {
         return null;
      }
   }

То же самое для строки с IRowContent:

   class Row : IColumnContent
   {
      public List<IRowContent> Content { get; private set; }

      //...
   }

ImageContent и TextContent реализуют оба интерфейса:

class TextContent : IRowContent, IColumnContent

class ImageContent : IRowContent, IColumnContent

Ответы [ 5 ]

3 голосов
/ 14 июля 2011

Если вы объявляете интерфейс

interface IRowContent 
{
    bool SupportsOtherChildren{ get; }
    ...
}

class ImageContent : IRowContent
{
    public bool SupportsOtherChildren
    {
        get { return false; }
    }
}

class Column : IRowContent
{
    public bool SupportsOtherChildren
    {
        get { return true; }
    }
}

Вы можете переопределить методы вставки и удаления коллекции для поддержки этого поведения:

 class RowContentCollection : Collection<IRowContent>
    {
        bool containsSingleItem = false;
        protected override void InsertItem(int index, IRowContent item)
        {
            if (containsSingleItem)
                throw new InvalidOperationException("Collection contains an item that doesnt allow other items.");

            containsSingleItem = !item.SupportsOtherChildren;

            base.InsertItem(index, item);
        }

        protected override void RemoveItem(int index)
        {
            if (!this[index].SupportsOtherChildren)
                containsSingleItem = false;

            base.RemoveItem(index);
        }
    }
1 голос
/ 14 июля 2011

Просто чтобы подвести итог и убедиться, что я вас правильно понимаю:

Класс Row должен содержать список столбцов. Каждый столбец может быть объектом типа Column, TextContent или ImageContent. Все три из этих классов реализуют интерфейс RowContent (который, по моему мнению, должен называться IColumnContent ...).

Если это так, то ограничение, которое вы пытаетесь навязать (если честно, я не совсем понимаю), это не вопрос дизайна класса, а вопрос логики добавления / удаления. Я бы объявил свойство Content как

private List<RowContent> m_internalColumns;

public RowContent[] Columns { get { return m_internalColumns.ToArray(); }}

и создайте Add и Remove методы, подобные следующему (псевдокод):

public void Add(RowContent column)
{
    if (adding column of type <typeof(column)> is allowed)
        m_internalColumns.Add(column);
}

public void Remove(RowContent column)
{
    m_internalColumns.Remove(column);
}
0 голосов
/ 14 июля 2011

Я бы, наверное, сделал одну из 2Либо:

Вместо использования Row.Content.Add() для добавления элементов, добавьте метод к Row для добавления содержимого.Row.AddContent(iRowContent content); и поместите свою «логику» в этот метод для определения, можно ли добавить какой-либо элемент.

Или, вместо использования List, реализовать свою собственную коллекцию, которая дополняет IList, и написать Add() метод таким образом, который содержит вашу логику.

0 голосов
/ 14 июля 2011

Абстрагируйте подробности о проблеме с самим интерфейсом.

public interface IRowContent
{
      bool SupportsChildren { get; }

      // other properties
}

Я бы также представил пользовательские методы Add и Remove для класса Row, которые определяют, может ли добавляемое содержимое поддерживать дополнительный контент.

0 голосов
/ 14 июля 2011

Вы можете сделать свой класс Row родовым:

class Row<T : IRowContent> {
    public List<T> Content { ... }
}

Тогда вы можете иметь Row<Column>, который может содержать только столбцы, или Row<TextContent>, который может содержать только текстовое содержимое. Вы даже можете иметь Row<IRowContent>, который допускает смешанный контент.

Если вам нужна строка, которая может содержать только текст и содержимое изображения (но без столбцов), добавьте межфансный интервал IRealContent : IRowContent и включите TextContent и ImageContent внедрите IRealContent. Тогда Row<IRealContent> может содержать только текст и изображения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...