В моем текущем дизайне фреймворка я просматриваю все типы конкретных сборок и работаю на основе найденных типов. Сборки, которые он ищет, определяются загрузчиком/инициализатором приложения. Сборки скомпилированы, поэтому на них можно строго ссылаться через:typeof(SomeTypeInTheAssembly).Assembly
. Это хорошо, потому что код загрузчика имеет строгую ссылку на тип в сборке, и нет возни с полными именами в виде встроенных строк, которые необходимо вручную поддерживать с датой -до -, если полное имя сборки изменится.. Но мне не нравилось ссылаться на какой-то совершенно не связанный тип в сборке и зависеть от его наличия. (Что, если он переместится на другую сборку? Что, если мы устарели/удалим тип? Изменить его пространство имен? )В коде это тоже выглядит немного странно:
FrameworkAssemblyReader.Read(typeof(SomeAssemblyNamespace.SubNamespace.GraphingCalculator).Assembly);
Теперь в моем коде начальной загрузки у меня есть прямая зависимость (, хотя довольно тривиальная зависимость )от GraphingCalculator
, которая не имеет ничего общего с стадией начальной загрузки (и как GraphingCalculator, она определенно не имеет ничего общего с получение ссылок на сборки ). Чтобы этого избежать, в каждой сборке, которую я намерен использовать таким образом, я добавил в их корень класс:
namespace SomeAssemblyNamespace
{
public static class AssemblyReference
{
public static System.Reflection.Assembly Get
{
get
{
return typeof(AssemblyReference).Assembly;
}
}
}
}
Что не так уж и плохо, потому что тогда мой код начальной загрузки выглядит как:
FrameworkAssemblyReader.Read(SomeAssembly.AssemblyReference.Get);
Но теперь у меня есть около дюжины или около того сборок с копированием/вставкой этого класса AssemblyReference
, и я ожидаю, что он будет продолжать расти по мере того, как приложения будут создаваться поверх фреймворка. Итак, мой вопрос: есть ли хороший способ избежать дублирования класса AssemblyReference
и по-прежнему программно передавать ссылки на сборки в базовую структуру, но при этом избегать нечеткости указания на какой-то произвольный/несвязанный тип в целевой сборке?Мои гуглы, кажется, говорят мне, что нет API или языковой функции, которая позволяет мне строго указывать на сборку (, например typeof
для классов ), но я надеюсь, что кто-то здесь придумал лучшее решение, чем я есть, что позволяет избежать дублирования класса/кода. Также следует отметить, что код иногда компилируется для Silverlight, поэтому я знаю, что это может привести к ограничению некоторых API/методов. Спасибо!
РЕДАКТИРОВАТЬ :Просто чтобы добавить еще один гаечный ключ, основываясь на ответе «енота», я должен упомянуть, что я не всегда загружаю одни и те же сборки. Например, у меня может быть сборка CarBuilding, которая применима для некоторых приложений, но не для всех. Загрузчики должны сказать мне, какие из них они хотят использовать (, а также любые пользовательские, которые использует разработчик )
. EDITx2 :Чтобы ответить на вопрос Джона Скита :Клиенты (или мы внутри компании )создадут любые проекты/DLL, которые они захотят поддерживать в своих приложениях. В свою очередь, эти проекты будут ссылаться на внутреннюю базовую структуру. Их проекты могут содержать ресурсы (3D-файлы, изображения, текст, локализацию и т. д. )и плагины -esque-классы (они реализуют сценарии, которые мы обнаруживаем и создаем/выполняем по мере необходимости. в течение всего срока службы приложения ). Кроме того, наша система предоставляет дополнительные модули (библиотеки DLL ), которые содержат подключаемые модули/контент многократного использования, которые клиенты (или мы )можем использовать при создании конкретных приложений. Таким образом, вы можете увидеть такую структуру проекта, как:
Solution
->MyAppBootstrapper_Android
->MyAppGUI_Android
->MyAppFramework
->MyAppResources
->MyAppAdditionalResources_Android
->MyAppBootstrapper_Silverlight
->MyAppGUI_Silverlight
->MyAppFramework
->MyAppResources
->MyAppAdditionalResources_Silverlight
->BaseFrameworkGraphingModule
Проекты загрузчика подключают зависимости и указывают, какие проекты/dll (сборки )должны быть предоставлены базовой структуре для обнаружения. Обратите внимание, что в этом случае «MyApp» использует собственную мини-инфраструктуру -и общие ресурсы как в сборках Android, так и в сборках Silverlight, но обе имеют свои собственные ссылки, независимые друг от друга.Silverlight использует преимущества BaseFrameworkGraphingModule
, и у них есть свои собственные ресурсы, специфичные для платформы.
Так вот в загрузчиках в проектах выглядят примерно так (пусть и упрощенно):
namespace MyAppBootstrapper_Android
{
public class Bootstrapper
{
public void Setup()
{
FrameworkAssemblyReader.Read(MyAppGUI_Android.AssemblyReference.Get);
FrameworkAssemblyReader.Read(MyAppFramework.AssemblyReference.Get);
FrameworkAssemblyReader.Read(MyAppResources.AssemblyReference.Get);
FrameworkAssemblyReader.Read(MyAppAdditionalResources_Android.AssemblyReference.Get);
}
}
}
namespace MyAppBootstrapper_Silverlight
{
public class Bootstrapper
{
public void Setup()
{
FrameworkAssemblyReader.Read(MyAppGUI_Silverlight.AssemblyReference.Get);
FrameworkAssemblyReader.Read(MyAppFramework.AssemblyReference.Get);
FrameworkAssemblyReader.Read(MyAppResources.AssemblyReference.Get);
FrameworkAssemblyReader.Read(MyAppAdditionalResources_Android.AssemblyReference.Get);
FrameworkAssemblyReader.Read(BaseFrameworkGraphingModule.AssemblyReference.Get);
}
}
}
Таким образом, для каждого приложения, созданного поверх базового фреймворка, создается загрузчик, который указывает, какие сборки включать (и какую-то другую не относящуюся к делу работу по подключению ). Чтобы конкретно ответить на этот вопрос, в проекте есть ссылки на время компиляции -для каждой необходимой сборки (, это выполняет двойную функцию, поскольку гарантирует, что все библиотеки DLL упакованы вместе для развертывания Android/Silverlight ), поскольку они не загружаются динамически в на смартфоне пользователя или в приложении Silverlight, но упакованы в первоначальную загрузку. Ваш вопрос о том, как загрузчики узнают, какие сборки использовать, хорошо, что разработчик знает и выполняет необходимые вызовы FrameworkAssemblyReader.Read
. Надеюсь, это поможет! Спасибо, что нашли время, чтобы посмотреть на него. У меня такое ощущение, что я делаю слишком много из ничего (или вообще упускаю гораздо лучшее решение/дизайн ).
Наконец, я позабыл (тупо )упомянуть, что мы также компилируем с помощью Mono для Android, а в ближайшем будущем и WPF. WinRT, скорее всего, появится в будущем, но я буду счастлив перейти по этому мосту, когда дело дойдет до этого. Однако, в целом, поскольку каждая из них компилируется по-своему со своими собственными функциями платформы, я не возражаю ужасно , если разные платформы по-разному извлекают ссылки на сборки; хотя было бы неплохо, если бы между платформами был единый синтаксис.
EDITx3 :Да, еще один. Я упомянул, но не уточнил на примере, что не все проекты нуждаются или должны читаться базовым фреймворком. Например, служебные программы или проекты бизнес-логики с кодом, не относящимся к базовой платформе, но относящимся к клиентскому приложению. Итак, из приведенного выше примера:
Solution
->MyAppBootstrapper_Android
->MyAppGUI_Android
->MyAppFramework
->MyAppResources
->MyAppAdditionalResources_Android
->MyCompanySharedUtilities
->MyAppBootstrapper_Silverlight
->MyAppGUI_Silverlight
->MyAppFramework
->MyAppResources
->MyAppAdditionalResources_Silverlight
->BaseFrameworkGraphingModule
->MyCompanySharedUtilities
MyCompanySharedUtilities
может использоваться MyAppGUI _Silverlight,и MyAppFramework, но разработчик может не запустить его через FrameworkAssemblyReader.Read
, потому что он содержит, скажем, только проприетарные реализации некоторых математических или бизнес-правил.