Click here to Skip to main content
15,887,409 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
Hello,
I have two classes ClassSender generates an event and ClassReceiver suppose to handle the event.
From what i have seen in the internet the Receiver class must have a reference to Sender class in order to register his handler of the event.
Is there a way to register on the event without having a reference of the Sender class?

Thanks
Posted

It is possible with dynamic subscription. You will need a mapper class that will help you achieve this. lets say you have a Publisher class that broadcast financial data periodically - Its keeps on running and whenever it has some new information it just publishes it:

for the broadcasting it has a delegate defined like following:

C#
public delegate void BroadcastData(string ticker, string command, decimal value);


Now there could be many subscribers interested in these broadcasts - but they may or may not be interested in the exact piece of information that is being published.

Lets assume that Subscriber S1 is interested in Ticker A, B and C and Command PriceClose where as S2 is interested in Ticker X, Y and Z and Command PriceClose & PriceOpen.

To solve this problem you need to put a mapper class - could be a singleton object.

See the example code - Here Subscriber gets the update from Publisher but not directly. Its the mapper who manages things between.

C#
public delegate void BroadcastData(string ticker, string command, decimal value);
public delegate void MarketUpdate(List<FinancialData> fData);

public class BroadcastingService {

    public static readonly BroadcastingService Instance = new BroadcastingService();

    public event BroadcastData OnDataUpdate;

    // This is a dummy implementation. in real world it will know what it has to publish when.
    private void Publish()
    {
        if (OnDataUpdate != null)
            OnDataUpdate("SomeTicker", "SomeCommand", 1000.00m);
    }
}

public class Subscriber
{
    public Subscriber() {
        Mapper.Register("IBM,VOD".Split(',').ToList(), "Priceclose,priceopen".Split(',').ToList(), HandleUpdate);
    }

    private void HandleUpdate(List<FinancialData> financialUpdate) {
        // DO clientside coding
    }
}

public class FinancialData {
    public string ticker;
    public string command;
    public decimal value;
}

public static class Mapper {

    static Dictionary<MarketUpdate, KeyValuePair<List<string>, List<string>>> Listners =
        new Dictionary<MarketUpdate, KeyValuePair<List<string>, List<string>>>();

    static List<FinancialData> allUpdate = new List<FinancialData>();
    static System.Threading.Timer timer = null;

    static Mapper() {
        BroadcastingService.Instance.OnDataUpdate += new BroadcastData(Instance_OnDataUpdate);
        timer = new System.Threading.Timer(st => {
            NotifySubscribers();
        });
        timer.Change(1000, 1000); // Update every second
    }

    static void Instance_OnDataUpdate(string ticker, string command, decimal value)
    {
        var fData = allUpdate.Find(fd => fd.ticker == ticker && fd.command == command);
        if (fData == null)
        {
            fData = new FinancialData() { ticker = ticker, command = command, value = value };
            allUpdate.Add(fData);
        }
        else {
            fData.value = value;
        }
    }

    public static void Register(List<string> tickers, List<string> commands, MarketUpdate callback)
    {
        Listners.Add(callback, new KeyValuePair<List<string>,List<string>>(tickers, commands));
    }
    public static void UnRegister(MarketUpdate callback) {
        Listners.Remove(callback);
    }

    public static void NotifySubscribers(){
        foreach (var lt in Listners)
        {
            List<FinancialData> financialUpdate = new List<FinancialData>();
            foreach (string tkr in lt.Value.Key)
            {
                foreach (string cmd in lt.Value.Value)
                {
                    var fData = allUpdate.Find(fd => fd.ticker == tkr && fd.command == cmd);
                    if (fData != null) {
                        financialUpdate.Add(fData);
                    }
                }
            }
            lt.Key.BeginInvoke(financialUpdate, null, null);
        }
    }
}


We can have such loose links; But to get update of course in the chain somewhere the reference of publisher has to be maintained. Its just that - it's a global Instance here who does this instead of subscriber doing so by itself.
 
Share this answer
 
v5
Not really - unless your event is static, which is very, very rare.

It's not normally a problem: normally the event is attached when you create the instance, and can be forgotten about from then on.
C#
ClassSender mySender = new ClassSender();
mySender.SenderEvent += new EventHandler(MyEventHandlerMethod);
If you haven't got an instance, then it's difficult to signal an event anyway because (unless all the code is static) no other code knows the instance exists!
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900