Приведенный ниже код в значительной степени резюмирует то, чего я хочу достичь.
У нас есть решение, которое включает в себя множество различных проектов, однако нам необходимо иметь возможность вызывать методы в проектах из проектов, на которые нет ссылок (это может вызвать циклическую ссылку).
Я опубликовал предыдущие вопросы, и приведенный ниже код в значительной степени является тем, что я придумал с помощью интерфейсов. Я до сих пор не знаю, как вызвать метод, находящийся в другом проекте, на который нет ссылок.
Я не могу создать экземпляр интерфейса, это должен быть класс. Но как я могу создать экземпляр класса, на который нет ссылок. Я не хочу использовать для этого отражение.
Код - C# 2.0
Любая помощь приветствуется.
Какой код мне нужно поместить в GeneralMethod (Class Raise), чтобы иметь возможность выполнить метод «Update» в классе «Listen»?
// Link Project
namespace Stack.Link
{
public class Interface
{
public interface Update
{
void Update();
}
}
}
// Project A
// References Link only
namespace Stack.ProjA
{
public class Raise
{
public void GeneralMethod()
{
// I want to place code in here to be able to execute
// "Update" method in ProjB.
// Keep in mind that ProjA and ProjB only reference
// Link Project
}
}
}
// Project B
// References Link only
namespace Stack.ProjB
{
public class Listen : Stack.Link.Interface.Update
{
public void Update()
{
// Do something here that is executed from ProjA
Console.Write("Executed Method in ProjB");
}
}
}
Мне, вероятно, следует прояснить мотивацию, стоящую за этим. Возможно, есть способ получше ....
У нас есть базовая форма, из которой сделаны ссылки на все остальные проекты. В качестве примера мы передаем объект, который содержит различные настройки в проект при его загрузке (из базовой формы).
Если, например, в объекте настроек изменились некоторые переменные (объект настроек заполнен в базовой форме), мы бы хотели, чтобы загруженный проект прослушал это изменение и получил новый объект настроек.
Поскольку базовая форма ссылается на все другие проекты, нам нужно, чтобы проекты «слушали» события в базовой форме.
Ясно как грязь :-)





Вам нужен проект Link, чтобы предоставить способ регистрации и создания конкретных реализаций интерфейсов. Затем ProjA зарегистрирует реализацию, и ProjB может запросить ее.
В ссылке на сборку:
public interface IThing { void Update(); }
public static class ThingRegistry {
public static void RegisterThing<T>() where T : IThing { ... }
public static T CreateThing<T>() where T : IThing { ... }
}
В сборке ProjA:
internal class Thing : IThing { public void Update() { ... } }
В сборке ProjB:
public class Listen {
public void UpdateThing() {
ThingRegistry.CreateThing<IThing>().Update();
}
}
Затем вы предоставляете какую-то конфигурацию, которая гарантирует, что ProjA зарегистрирует ее реализацию до того, как ProjB запросит ее.
Более простой способ - использовать фреймворк внедрения зависимостей для управления этим материалом или перегруппировать ваши проекты по уровням без циклических зависимостей.
Мне, вероятно, следует прояснить мотивацию, стоящую за этим. Возможно, есть способ получше ....
У нас есть базовая форма, из которой сделаны ссылки на все остальные проекты. В качестве примера мы передаем объект, который содержит различные настройки в проект при его загрузке (из базовой формы).
Если, например, в объекте настроек изменились некоторые переменные (объект настроек заполнен в базовой форме), мы бы хотели, чтобы загруженный проект прослушал это изменение и получил новый объект настроек.
Поскольку базовая форма ссылается на все другие проекты, нам нужно, чтобы проекты «слушали» события в базовой форме.
Ясно, как грязь. :-)
Джаспер. Пожалуйста, отредактируйте свой вопрос и поместите эту «информацию» туда, этот ответ БУДЕТ отклонен полицией SO, если вы этого не сделаете.
Другой вариант - определить модель подписчика издателя. Итак, в вашем проекте ссылки (проект, на который ссылаются все проекты) у вас может быть что-то вроде (это псевдо-код, поэтому он не будет компилироваться сам по себе, но приблизит вас:
public class EventBroadcaster {
//use your singleton pattern of choice. This is not what I would reocmmend but its short
private static EventBroadcaster Instance=new EventBroadcaster;
public void RegisterForEvent(string key,Delegate del)
{
//Store the delegate in a dictionary<string,del>
//You can also use multicast delegates so if your settings object changes notify all people who need it
}
public void FireEvent(string key,EventArgs e)
{
//Get the item and execute it.
}
}
Теперь вы можете определить свою собственную подпись для своего делегата, чтобы вы могли передать любое состояние, которое хотите, в своем собственном классе аргументов настраиваемого события. Когда каждый листерн просыпается, попросите его зарегистрироваться для своих событий ... вы также должны реализовать отмену регистрации.
приятно то, что вы можете заставить любую часть вашего приложения взаимодействовать с любой другой частью, не связывая их вообще.
Вот статья о чем-то похожем на то, что мы использовали. У него была статья получше, но я пока не могу ее найти: http://www.codeproject.com/KB/cs/eventpool.aspx
Вот продолжение, в котором используются дженерики: http://www.codeproject.com/KB/cs/EventPool_Revisited.aspx
Джош, спасибо ... твоя идея звучит хорошо. можете ли вы предоставить более конкретный код, который мы можем реализовать? Псевдо-код приближает нас, но не выходит за рамки.
После того, как мы реализовали это, кто-то уронил мне на стол статью о проекте ... она была так близка к тому, что мы делали, было страшно, позвольте мне найти ее для вас ...
спасибо еще раз за ссылки. Я загрузил проект eventpool и пытаюсь лучше его понять. Жаль, что образец не работает ... иногда все, что вам нужно, это увидеть его реализованным, чтобы получить ощущение «ах, вот как это работает».
Если у меня будет время, я посмотрю, смогу ли я собрать образец. Я никогда не использовал его код, но он выглядел так близко к тому, что есть у нас ... Если вы решите эту проблему, дайте мне знать, чтобы я не терял время ...
Простое решение:
Класс "Raise" в проекте Ссылки на проект Ссылка. Таким образом, он может вызывать методы непосредственно для определенных там объектов.
Что-то в ссылке на проект будет вызываться классом Raise. Затем ему нужно вызвать событие.
Класс «Слушать» может прослушивать это событие и реагировать.
похоже, что это могло бы сработать ... но как «Listen» подписаться на события в проекте Link, если экземпляр Link создается после создания экземпляра «Listen». Насколько я понимаю, слушателю нужно подписаться на существующий экземпляр.
Для этого я использовал Activator.CreateInstance. Вы загружаете сборку по пути, а затем создаете экземпляр класса. Например, вы можете использовать это для загрузки сборок гаджетов в хост-приложение, где хост не знает о гаджетах во время компиляции.
Пример псевдокода (без обработки ошибок)
Создайте интерфейс для класса, который вы собираетесь загрузить:
public interface IRemote
{
void Update();
}
Затем вам понадобится метод для загрузки сборки и вызова функции
Теперь вот способ использовать все это:
private void
DoRemoteUpdate( string assemblyPath, string className )
{
Assembly assembly = Assembly.Load(assemblyPath);
Type objectType = assembly.GetType(className);
remoteAssembly = (IRemote)Activator.CreateInstance(objectType);
remoteAssembly.Update();
}
Также ... взгляните на структуру управляемой расширяемости