views:

4641

answers:

5

The code below pretty much sums up what I want to achieve.

We have a solution which comprises many different projects however we have a need to be able to call methods in projects from projects which are not referenced (would cause circular reference).

I have posted previous questions and the code below is pretty much what I have come up with using interfaces. I still do not know how I can call a method that resides in a different project that is not referenced.

I cannot create an instance of the interface, it has to be a class. But how can I create an instance of a class that is not referenced. I do not want to use reflection for this.

Code is C# 2.0

Any help is appreciated.

What code do I need to place in "GeneralMethod" (Class Raise) to be able to execute the "Update" method in Class "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");
        }
    }
}

I should probably clarify the motivation behind needing to do this. Perhaps there is a better way ....

We have a baseform from which all other projects are referenced. As an example we pass an object which contains various settings to the project when it is loaded (from the baseform).

If for example, the settings object has some variables change (settings object populated in baseform), we would like the loaded project to listen for this change and obtain a new settings object.

Because the baseform references all the other projects, we need to have the projects "listen" for events in the baseform.

Clear as mud :-)

+1  A: 

You need the Link project to provide a way of registering and constructing concrete implementations of the interfaces. Then ProjA will register an implementation and ProjB can request it.

In assembly Link:

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 { ... }
}

In assembly ProjA:

internal class Thing : IThing { public void Update() { ... } }

In assembly ProjB:

public class Listen { 
  public void UpdateThing() {
    ThingRegistry.CreateThing<IThing>().Update();
  }
}

Then you provide some sort of configuration that makes sure ProjA registers it's implementation before ProjB requests it.

An easier way is to use a dependency injection framework to manage that stuff for you or rearrange your projects into layers with no circular dependencies.

Andrew Kennan
A: 

I should probably clarify the motivation behind needing to do this. Perhaps there is a better way ....

We have a baseform from which all other projects are referenced. As an example we pass an object which contains various settings to the project when it is loaded (from the baseform).

If for example, the settings object has some variables change (settings object populated in baseform), we would like the loaded project to listen for this change and obtain a new settings object.

Because the baseform references all the other projects, we need to have the projects "listen" for events in the baseform.

Clear as mud :-)

Jasper. Please edit your question and put this "information" there, this answer WILL be voted down by the SO police if you don't.
Binary Worrier
A: 

Another option would to be define a a publisher subscriber model. So in your link project (The project which all projects reference) you could have something like (This is psuedo code so will not compile on its own but get you close:

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. 
   }
}

Now you can define your own signature for your delegate so you can pass whatever state you want in your own custom event args class. When each listern wakes up have them Register for their events...you should also implement an unregister.

the nice thing is you can have any part of your app talking to any other part without them being coupled at all.

Edited

Here's an article on something simillar to what we used He had a better article before but I can;t find it yet: http://www.codeproject.com/KB/cs/eventpool.aspx

Here's a followup taking generics into accoutn: http://www.codeproject.com/KB/cs/EventPool_Revisited.aspx

JoshBerke
Josh, thnx ... your idea sounds good. can you provide more concrete code that we can implement? The psuedo code gets us close but not over the line.
After we implemented this someone dropped a codeproject article on my desk...it was so close to what we were doing it was scarry let me find that for you...
JoshBerke
thnx again for the links. i have downloaded the eventpool project and I am trying to understand it better. too bad the sample does not work ... sometimes all you need is to see it implemented to get that "ah thats how it works" feeling.
If I get some time I'll see if I can pull together a sample. I never used his code but it looked so close to what we have... If you resolve this let me know so I don't waste any time...
JoshBerke
a sample would be great.
A: 

Simple solution:

Class "Raise" in project A references project Link. So it can call methods directly on objects defined there.

Something in project link is going to be called by class Raise. It then needs to raise an event.

Class "Listen" can listen for that event and react.

Nigel Hawkins
this sounds like it could work ... but how can "Listen" subscribe to events in project Link if the instance of Link is created after the creation of the "Listen" instance. From my understanding, the listener need to subscribe to an existing instance.
+1  A: 

I use Activator.CreateInstance to do this. You load the assembly from a path and then create an instance of the class. For example, you could use this to load gadgets assemblies in a host application where the host doesnt know about the gadgets at compile time.

Sample Pseudo Code (no error handling)

Create an interface for the class you are going to load:

public interface IRemote { void Update(); }

Then you need a method to load the Assembly and call the function

Now here is a method to use all this:

private void DoRemoteUpdate( string assemblyPath, string className ) { Assembly assembly = Assembly.Load(assemblyPath); Type objectType = assembly.GetType(className);

remoteAssembly = (IRemote)Activator.CreateInstance(objectType); remoteAssembly.Update(); }

Marcus Erickson