[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;
}