Рейтинговые книги
Читем онлайн Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 216 217 218 219 220 221 222 223 224 ... 407
class="code">CSharpSnapIn и VBSnapIn.

Добавление событий PostBuild

Откройте окно свойств проекта для CSharpSnapIn (щелкнув правой кнопкой мыши на имени проекта в окне Solution Explorer и выбрав в контекстном меню пункт Properties (Свойства)) и перейдите в нем на вкладку Build Events (События при компиляции). Щелкните на кнопке Edit Post-build (Редактировать события после компиляции) и затем щелкните на Macros>> (Макросы). Здесь вы можете видеть доступные для использования макросы, которые ссылаются на пути и/или имена файлов. Преимущество применения этих макросов в событиях, связанных с компиляцией, заключается в том, что они не зависят от машины и работают с относительными путями. Скажем, кто-то работает в каталоге по имени c-sharp-wfcodechapterl7. Вы можете работать в другом каталоге (вероятнее всего так и есть). За счет применения макросов инструмент MSBuild всегда будет использовать корректный путь относительно файлов *.csproj.

Введите в области PostBuild (После компиляции) следующие две строки:

copy $(TargetPath) $(SolutionDir)MyExtendableApp$(OutDir)$(TargetFileName) /Y

copy $(TargetPath) $(SolutionDir)MyExtendableApp$(TargetFileName) /Y

Сделайте то же самое для проекта VBSnapin, но здесь вкладка в окне свойств называется Compile (Компиляция) и на ней понадобится щелкнуть на кнопке Build Events (События при компиляции).

Когда показанные выше команды событий после компиляции добавлены, все сборки при каждой компиляции будут копироваться в каталог проекта и выходной каталог приложения MyExtendableApp.

Построение сборки CommonSnappableTypes.dll

Удалите стандартный файл класса Class1.cs из проекта CommonSnappableTypes, добавьте новый файл интерфейса по имени AppFunctionality.cs и поместите в него следующий код:

namespace CommonSnappableTypes

{

  public interface IAppFunctionality

  {

    void DoIt();

  }

}

Добавьте файл класса по имени CompanyInfoAttribute.cs и приведите его содержимое к такому виду:

using System;

namespace CommonSnappableTypes

{

  [AttributeUsage(AttributeTargets.Class)]

  public sealed class CompanyInfoAttribute : System.Attribute

  {

    public string CompanyName { get; set; }

    public string CompanyUrl { get; set; }

  }

}

Тип IAppFunctionality обеспечивает полиморфный интерфейс для всех оснасток, которые могут потребляться расширяемым приложением. Учитывая, что рассматриваемый пример является полностью иллюстративным, в интерфейсе определен единственный метод под названием DoIt().

Тип CompanyInfoAttribute — это специальный атрибут, который может применяться к любому классу, желающему подключиться к контейнеру. Как несложно заметить по определению класса, [CompanyInfо] позволяет разработчику оснастки указывать общие сведения о месте происхождения компонента.

Построение оснастки на C#

Удалите стандартный файл Class1.cs из проекта CSharpSnapIn и добавьте новый файл по имени CSharpModule.cs. Поместите в него следующий код:

using System;

using CommonSnappableTypes;

namespace CSharpSnapIn

{

  [CompanyInfo(CompanyName = "FooBar", CompanyUrl = "www.FooBar.com")]

  public class CSharpModule : IAppFunctionality

  {

    void IAppFunctionality.DoIt()

    {

      Console.WriteLine("You have just used the C# snap-in!");

    }

  }

}

Обратите внимание на явную реализацию интерфейса IAppFunctionality (см. главу 8). Поступать так необязательно; тем не менее, идея заключается в том, что единственной частью системы, которая нуждается в прямом взаимодействии с упомянутым интерфейсным типом, будет размещающее приложение. Благодаря явной реализации интерфейса IAppFunctionality метод DoIt() не доступен напрямую из типа CSharpModule.

Построение оснастки на Visual Basic

Теперь перейдите к проекту VBSnapIn. Удалите файл Class1.vb и добавьте новый файл по имени VBSnapIn.vb. Код Visual Basic столь же прост:

Imports CommonSnappableTypes

<CompanyInfo(CompanyName:="Chucky's Software", CompanyUrl:="www.ChuckySoft.com")>

Public Class VBSnapIn

  Implements IAppFunctionality

  Public Sub DoIt() Implements CommonSnappableTypes.IAppFunctionality.DoIt

    Console.WriteLine("You have just used the VB snap in!")

  End Sub

End Class

Как видите, применение атрибутов в синтаксисе Visual Basic требует указания угловых скобок (<>), а не квадратных ([]). Кроме того, для реализации интерфейсных типов заданным классом или структурой используется ключевое слово Implements.

Добавление кода для ExtendableApp

Последним обновляемым проектом является консольное приложение C# (MyExtendableApp). После добавления к решению консольного приложения MyExtendableApp и установки его как стартового проекта добавьте ссылку на проект CommonSnappableTypes, но не на CSharpSnapIn.dll или VbSnapIn.dll. Модифицируйте операторы using в начале файла Program.cs, как показано ниже:

using System;

using System.Linq;

using System.Reflection;

using CommonSnappableTypes;

Метод LoadExternalModule() выполняет следующие действия:

• динамически загружает в память выбранную сборку;

• определяет, содержит ли сборка типы, реализующие интерфейс IAppFunctionality;

• создает экземпляр типа, используя позднее связывание.

Если обнаружен тип, реализующий IAppFunctionality, тогда вызывается метод DoIt() и найденный тип передается методу DisplayCompanyData() для вывода дополнительной информации о нем посредством рефлексии.

static void LoadExternalModule(string assemblyName)

{

  Assembly theSnapInAsm = null;

  try

  {

    // Динамически загрузить выбранную сборку.

    theSnapInAsm = Assembly.LoadFrom(assemblyName);

  }

  catch (Exception ex)

  {

    // Ошибка при загрузке оснастки

    Console.WriteLine($"An error occurred loading the snapin: {ex.Message}");

    return;

  }

  // Получить все совместимые c IAppFunctionality классы в сборке.

  var theClassTypes = theSnapInAsm

      .GetTypes()

      .Where(t => t.IsClass && (t.GetInterface("IAppFunctionality") != null))

      .ToList();

  if (!theClassTypes.Any())

  {

    Console.WriteLine("Nothing implements IAppFunctionality!");

                 // Ни один класс не реализует IAppFunctionality!

  }

  // Создать объект и вызвать метод DoIt().

  foreach (Type t in theClassTypes)

  {

    /// Использовать позднее связывание для создания экземпляра типа.

    IAppFunctionality itfApp =

        (IAppFunctionality) theSnapInAsm.CreateInstance(t.FullName, true);

    itfApp?.DoIt();

    // Отобразить информацию о компании.

    DisplayCompanyData(t);

  }

}

Финальная задача связана с отображением метаданных, предоставляемых атрибутом [CompanyInfo]. Создайте метод DisplayCompanyData(), который принимает параметр System.Туре:

static void DisplayCompanyData(Type t)

{

  // Получить данные [CompanyInfo].

  var compInfo = t

    .GetCustomAttributes(false)

    .Where(ci =>

1 ... 216 217 218 219 220 221 222 223 224 ... 407
На этой странице вы можете бесплатно читать книгу Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен бесплатно.

Оставить комментарий