logo

[ELMA3] Расширяемые интерфейсы для моделей данных на основе IAutoImplement

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

/// <summary>
/// Базовый тип для автореализуемых интерфейсов
/// </summary>
[ExtensionPoint(false)]
[Component]
[DeveloperApi(DeveloperApiType.ExtensionPoint)]
public interface IAutoImplement
{
}

Точка расширения IAutoImplement позволяет позволяет расширять модели данных, находящихся в разных сборках. Пример: ICommentActionModel - модель для действия с комментариями и файловыми вложениями (Модуль EleWise.ELMA.Common) и ICommentWithDocumentsActionModel - расширение для модели действия с комментарием для добавления прикрепленных документов (Модуль EleWise.ELMA.Documents).

/// <summary>
/// Модель для действия с комментарияем и файловыми вложениями
/// </summary>
public interface ICommentActionModel : IAutoImplement
{
    /// <summary>
    /// Комментарий
    /// </summary>
    [global::EleWise.ELMA.Model.Attributes.DisplayName(typeof(@__Resources_ICommentActionModel), "P_Comment_DisplayName")]
    IComment Comment { get; set; }

    /// <summary>
    /// Вложения
    /// </summary>
    [global::EleWise.ELMA.Model.Attributes.DisplayName(typeof(@__Resources_ICommentActionModel), "P_Attachments_DisplayName")]
    IList<IAttachment> Attachments { get; set; }

    /// <summary>
    /// Файлы для копирования в текущий объект
    /// </summary>
    [global::EleWise.ELMA.Model.Attributes.DisplayName(typeof(@__Resources_ICommentActionModel), "P_CopiedAttachments_DisplayName")]
    IList<IAttachment> CopiedAttachments { get; set; }
}

Для того, чтобы ICommentWithDocumentsActionModel был расширением ICommentActionModel, следует добавить атрибут InterfaceExtensionAttribute.

/// <summary>
/// Расширение для модели действия с комментарияем. Добавляет прикрепленные документы
/// </summary>
[InterfaceExtension(typeof(ICommentActionModel))]
public interface ICommentWithDocumentsActionModel : ICommentActionModel
{
    /// <summary>
    /// Прикрепленные документы
    /// </summary>
    [DisplayName("Прикрепленные документы")]
    IList<IDocumentAttachment> DocumentAttachments { get; set; }

    /// <summary>
    /// Документы для копирования в текущий объект
    /// </summary>
    [DisplayName("Документы для копирования в текущий объект")]
    IList<IDocumentAttachment> CopiedDocumentAttachments { get; set; }
}

Таким образом при построении динамической сборки будет сгенерирован реальный класс, который содержит в себе свойства интерфейса ICommentActionModel и его расширений. Класс CommentActionModel в dotPeek:

using EleWise.ELMA.ComponentModel;
using EleWise.ELMA.Documents.Models;
using EleWise.ELMA.Model.Attributes;
using EleWise.ELMA.Model.Common;
using System.Collections.Generic;

namespace EleWise.ELMA.Common.Models
{
  /// <summary>
  /// Автоматическая реализация интерфейса EleWise.ELMA.Common.Models.ICommentActionModel
  /// </summary>
  [Component]
  [Implement(typeof (ICommentWithDocumentsActionModel))]
  [Implement(typeof (ICommentActionModel))]
  public class CommentActionModel : ICommentWithDocumentsActionModel, ICommentActionModel, IAutoImplement
  {
    private IComment _comment;
    private IList<IAttachment> _attachments;
    private IList<IAttachment> _copiedAttachments;
    private IList<IDocumentAttachment> _documentAttachments;
    private IList<IDocumentAttachment> _copiedDocumentAttachments;

    /// <summary>Комментарий</summary>
    [PropertyDeclarationType(typeof (ICommentActionModel))]
    public virtual IComment Comment
    {
      get
      {
        return this._comment;
      }
      set
      {
        this._comment = value;
      }
    }

    /// <summary>Прикрепленные файлы</summary>
    [PropertyDeclarationType(typeof (ICommentActionModel))]
    public virtual IList<IAttachment> Attachments
    {
      get
      {
        return this._attachments;
      }
      set
      {
        this._attachments = value;
      }
    }

    /// <summary>Файлы для копирования в текущий объект</summary>
    [PropertyDeclarationType(typeof (ICommentActionModel))]
    public virtual IList<IAttachment> CopiedAttachments
    {
      get
      {
        return this._copiedAttachments;
      }
      set
      {
        this._copiedAttachments = value;
      }
    }

    /// <summary>Прикрепленные документы</summary>
    [PropertyDeclarationType(typeof (ICommentWithDocumentsActionModel))]
    public virtual IList<IDocumentAttachment> DocumentAttachments
    {
      get
      {
        return this._documentAttachments;
      }
      set
      {
        this._documentAttachments = value;
      }
    }

    /// <summary>Документы для копирования в текущий объект</summary>
    [PropertyDeclarationType(typeof (ICommentWithDocumentsActionModel))]
    public virtual IList<IDocumentAttachment> CopiedDocumentAttachments
    {
      get
      {
        return this._copiedDocumentAttachments;
      }
      set
      {
        this._copiedDocumentAttachments = value;
      }
    }
  }
}

Для того, чтобы работать с свойствами расширяемой модели, достаточно использовать приведение типов. Например, с помощью оператора as:

var actionModel = InterfaceActivator.Create<ICommentActionModel>();
actionModel.Comment = InterfaceActivator.Create<IComment>();
actionModel.Comment.Text = text;
actionModel.Attachments = attachments;
var documentActionModel = actionModel as ICommentWithDocumentsActionModel;
if (documentActionModel != null)
{
    documentActionModel.DocumentAttachments = documentAttachments;
}