C# Шаблон конструктора на основе методов класса - PullRequest
0 голосов
/ 06 марта 2020

Мне нужно создать систему, которая будет учитывать текущую сборку и выполнять x действие, основанное на этом (отражение).

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

Основная проблема в том, что у меня разные аргументы для разных классов (я наследую от абстрактного класса)

Базовый класс:

public abstract class HelpItem : INotifyPropertyChanged
{
    public HelpItem()
    {

    }

    string group;
    SvgImage image;
    string description;
    string help;
    string name;

    public string Name
    {
        get { return name; }
        set
        {
            name = value;
        }
    }


    public string Help
    {
        get { return help; }
        set
        {
            if (help == value)
                return;
            help = value;
            OnPropertyChanged(this, new PropertyChangedEventArgs(nameof(Help)));
        }
    }


    public string Group
    {
        get { return group; }
        set
        {
            if (group == value)
                return;
            group = value;
            OnPropertyChanged(this, new PropertyChangedEventArgs(nameof(Group)));
        }
    }


    public string Description
    {
        get { return description; }
        set
        {
            if (description == value)
                return;
            description = value;
            OnPropertyChanged(this, new PropertyChangedEventArgs(nameof(Description)));
        }
    }


    public SvgImage Image
    {
        get { return image; }
        set
        {
            if (image == value)
                return;
            image = value;
            OnPropertyChanged(this, new PropertyChangedEventArgs(nameof(Image)));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        PropertyChanged?.Invoke(sender, e);
    }

    [Action("&Open")]
    public abstract void Run();

    public static IList<HelpAttribute> GetHelpItems()
    {
        return GetHelpItems<HelpItem>();
    }


}

Использование этого класса будет:

    public class PfdHelpItem : HelpItem
{
    public PfdHelpItem(System.IO.MemoryStream stream, DevExpress.XtraBars.Docking2010.DocumentManager docManager)
    {
        DocManager = docManager;
        Stream = stream;
    }

    public MemoryStream Stream { get; set; }
    public DocumentManager DocManager { get; set; }

    bool isExternal;

    public bool IsExternal
    {
        get { return isExternal; }
        set
        {
            if (isExternal == value)
                return;
            isExternal = value;
            OnPropertyChanged(this, new PropertyChangedEventArgs(nameof(IsExternal)));
        }
    }

    public override void Run()
    {
        ...
    }

    [Action("Open &externally")]
    public void RunExternal()
    {
        ...
    }

    [Action("&Save as...")]
    public void SaveAs()
    {
       ...
    }
}

Класс атрибута:

public abstract class HelpAttribute : Attribute
{
    public HelpAttribute(string name, string title, string description)
    {
        Description = description;
        Title = title;
        Name = name;
    }

    public string Name { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
}

Тогда у меня есть другие дочерние классы:

public class PdfHelpAttribute : HelpAttribute
{
    public PdfHelpAttribute(string name, string title, string description) 
        : base(name, title, description)
    {

    }
}

Затем используйте этот атрибут:

    /// <summary>
    ///   Looks up a localized resource of type System.Byte[].
    /// </summary>
    [Misc.Help.PdfHelp("MyFileName", "Title", "Desc")]
    internal static byte[] MyPdfFile{
        get {
            object obj = ResourceManager.GetObject("MyPdfFile", resourceCulture);
            return ((byte[])(obj));
        }
    }

Так, как показано в примере, в этом случае он будет получать файлы PDF из ресурса и обрабатывать его, откройте , save, et c.

Также есть класс OnlineHelp, который заполнен URL-адресами и имеет другие действия.

Идея состоит в том, чтобы получить все элементы HelpItems из отражения и отобразить их по мере необходимости. .

Есть ли известный шаблон для работы с такой ситуацией?

Заранее спасибо!

1 Ответ

1 голос
/ 06 марта 2020

Можно использовать следующий шаблон:

  1. Определите интерфейс для желаемой функциональности, которую вы хотите найти.
  2. Реализуйте интерфейс в абстрактном базовом классе.
  3. Создание класса инвентаря.
  4. Инициализация класса инвентаря с набором сборок. Этот набор может быть определен статически или динамически определен путем циклического перебора доступных сборок в домене приложения.
  5. L oop для всех типов сборок.
  6. L oop через все интерфейсы в этих типах (и базовых типах)
  7. Составьте список доступных типов, реализующих различные интерфейсы, используя соответствующую структуру.
  8. Добавьте метод для получения доступных типов во время выполнения при необходимости.

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

Пример : Посмотрите на Initialize и GetTypesImplementingInterface методы в классе c Types класса Waher.Runtime.Inventory nuget:

https://github.com/PeterWaher/IoTGateway/blob/master/Runtime/Waher.Runtime.Inventory/Types.cs

Его можно комбинировать с классом TypesLoader для динамической загрузки всех доступных сборок во время запуска:

https://github.com/PeterWaher/IoTGateway/blob/master/Runtime/Waher.Runtime.Inventory.Loader/TypesLoader.cs

...