Use Delegate and Event in CSharp to have Tell Don’t Ask

Feb 27, 2013 00:00 · 531 words · 3 minute read Programming C# example type delegate event tell don't ask

What is Tell don’t ask?

In this pattern we make our decision and then tell object what you want them to do rather than asking them about their state. It is okay to get state of an object , as long as do not use them to make decisions on the caller side .Once, you start making decisions based on object properties then you violating object encapsulation.

It also helps us to decouple the responsibilities and preventing to violating the Law of Demeter (source 1, source 2).

What is an event ?

Event help us to notify other classes or objects when something interesting happening. The publisher raises an event and the subscribers handle it (source 3).

What we are going to achieve?

Test class

[TestFixture]
public class TestTellDontAsk {
      [Test]
      public void Given_Message_When_SendCommunication_Then_ShouldSendWithSmsAndEmail() {
          var tellDontAsk = new TellDontAsk();
          tellDontAsk.RegisterCommunication(new Message());
          var senderEventHandlerArgs = new SenderEventHandlerArgs(){IsEmailSent = false,IsSmsSent = false};
          tellDontAsk.sendMessage("test message", senderEventHandlerArgs);
          Assert.IsTrue(senderEventHandlerArgs.IsEmailSent);
          Assert.IsTrue(senderEventHandlerArgs.IsSmsSent); 
      }
}

I wish to have TellDontAsk class that I can wire up Message methods to it and when Asking it to SendMessage, it starts sending this message to all of the registered methods.

Make TellDontAsk class

Tell Dont ask class

public class TellDontAsk {
public SendCommunication sender;
	public void RegisterCommunication(Message message) {
		sender += message.SendMessageWithEmail;
		sender += message.SendMessageWithSms;
	}
	
	public void sendMessage(string TextMessage, SenderEventHandlerArgs args) {
		sender(TextMessage, args);
	}
}

We are registering the Message class methods with SendCommunication delegate.

delegate

public delegate void SendCommunication(string message, SenderEventHandlerArgs args);

This delegate will help us to handling all methods that have ‘Void’ return type and accepting ‘string’ with ‘SenderEventHandlerArgs’.

Therefore when we call Sender it will call ‘SendmessageWithEmail and SendMessageWithSms’ methods.

Message Class

The Message class will have our communication Methods.

Message class

public void SendMessageWithEmail(string message, SenderEventHandlerArgs args) {
	Console.WriteLine("Email this message {0}", message);
	//sending message with email
	args.IsEmailSent = true;
	senderEvent(this, args);
}

event

public event EventHandler<SenderEventHandlerArgs> senderEvent;

The method will send the email in this step and then raise an event to let others know about it .

The SenderEvent will handle all the event that is a SenderEventHandlerArgs and we should attach this event with our code by the below anonymous method.

attache event in constructor

public Message() {
	senderEvent = delegate( object s,  SenderEventHandlerArgs e) { };
}

Therefore anytime this event is raised it will be cached and update our SenderEventHandlerArgs properties that derived from EventArgs class.

eventArgs

public class SenderEventHandlerArgs : EventArgs {
            public bool IsEmailSent { get; set; }
            public bool IsSmsSent { get; set; }
}

We can do the same scenario for sendingSms

Send message method

public void SendMessageWithSms(string message, SenderEventHandlerArgs args) {
	Console.WriteLine("Sms this mesksage {0}", message);
	//sending message with Sms
	args.IsSmsSent = true;
	senderEvent(this, args);
}
What will be happening?

Methods of Message class will be registered to the ‘SendCommucation’ handelerand they will be called when we calling SendMessage method in the order. Each method will be notifying us about the status of Email and Sms by raising SenderEvent event and it will be handled with anonymous method that can be more grounded in the future according to our needs.

Download

Feel free to download the full source of this example from my GitHub.