I'm facing a similar scenario to this issue and I was wondering if it's possible to get around a cleaner solution.
Supposing we have a party that has People on it, We have the interface:
public interface IPerson {
void Arrive();
void Dance();
}
And its implementations, people that are able to dance
public class PersonThatCanDance : IPerson {
public void Arrive() {
//Logic related to arriving
}
public void Dance() {
//Logic related to dancing
}
}
and those who aren't
public class PersonThatCannotDance : IPerson {
public void Arrive() {
//Logic related to arriving
}
public void Dance() {
}
}
Knowing this, now we have the party with 2 people
public class Party {
private IPerson person1;
private IPerson person2
private void StartParty() {
person1.Arrive();
person2.Arrive();
}
private void StartMusic() {
person1.Dance();
person2.Dance();
}
}
With this scenario settled, the problem comes when we want to make the party not care if the person is a person that can dance or not. The party throws the people into dancing no matter if they have functionality to do so.
From what I understand, the existence of the Dance() method in PersonThatCannotDance is a violation of ISP but making the party not care about what kind of person is preventing me from respecting the principle.
Is there a way to get around this? Thank you.
yes you are right. it is violation of ISP.
public interface IArrive : IPerson {
void Arrive();
DateTime Time {get;set;}
string Mode {get;set;}
}
public interface IDance: IPerson {
void Dance();
DateTime duration {get;set;}
string Type {get;set;}
}
public interface IPerson {
string Name {get;set;}
void Dress();
}
Now Implementations looks like this, people that are able to dance
public class PersonThatCanDance : IArrive,IDance {
string Name {get; set;}
public void Dress() {
//Logic related to arriving
}
public void Arrive() {
//Logic related to arriving
}
public void Dance() {
//Logic related to dancing
}
}
and those who aren't
public class PersonThatCannotDance : IArrive {
string Name {get; set;}
public void Dress() {
//Logic related to arriving
}
public void Arrive() {
//Logic related to arriving
}
}
In Party Class
public class Party {
private IPerson person1 = new PersonThatCanDance();
private IPerson person2 = new PersonThatCannotDance();
private void StartParty() {
((IArrive)person1).Arrive();
((IArrive)person2).Arrive();
}
private void StartMusic() {
if(person1 is IDance)
{
((IDance)person1).Dance();
}
if(person2 is IDance)
{
((IDance)person2).Dance();
}
}
}
Now I hope this solution will work. please let me know if still have doubt.
There is not enough information to determine the right design for your situation, but I can offer a design that's broadly applicable:
public interface IPerson {
void Arrive();
}
public class PersonThatCanDance : IPerson {
public void Arrive(Party party) {
//Logic related to arriving
...
party.AddDancers(this);
}
public void Dance() {
//Logic related to dancing
...
}
}
public class PersonThatCannotDance : IPerson {
public void Arrive(Party party) {
//Logic related to arriving
...
}
}
public class Party {
private IPerson person1;
private IPerson person2;
ArrayList dancers = new ArrayList();
private void StartParty() {
person1.Arrive(this);
person2.Arrive(this);
}
public void AddDancers(PersonThatCanDance dancer) {
dancers.Add(dancer);
}
private void StartMusic() {
for (var dancer in dancers) {
dancer.Dance();
}
}
}
A possibly more idiomatic alternative, is going by events.
public class PersonThatCanDance : IPerson {
public void Arrive(Party party) {
//Logic related to arriving
...
party.OnCueMusic(this.Dance);
}
...
}
public class Party {
public delegate void Dance();
ArrayList musicEvents = new ArrayList();
...
public void OnCueMusic(Dance dance) {
musicEvents.Add(dance);
}
private void StartMusic() {
for (var musicEvent in musicEvents) {
musicEvent();
}
}
}
Related
I have PhotoBase class
public abstract class PhotoBase
{
public string Path { get; set; }
}
And I have multiple derived classes, for example the path may indicate a location in the file system or an external url.
public class FilePhoto : PhotoBase {}
public class ExternalPhoto : PhotoBase {}
I want to load these photos, I have a PhotoLoader class like below:
public class PhotoLoader
{
public void Load(FilePhoto Photo)
{
// get the photo from file system
}
public void Load(ExternalPhoto Photo)
{
// download the photo from path
}
}
Now I want to load these photos, so I have to do:
public class PhotoImporter
{
private PhotoLoader _photoLoader;
public PhotoImporter(PhotoLoader photoLoader)
{
_photoLoader = photoLoader;
}
public void ImportPhoto(PhotoBase photo)
{
if (photo is FilePhoto)
{
_photoLoader.Load(photo as FilePhoto);
}
if (photo is ExternalPhoto)
{
_photoLoader.Load(photo as ExternalPhoto);
}
}
}
I have several derived classes and I may add more photo types in the future. Is there a more elegant way that I could get rid of if conditions? Using factory pattern?
Another approach would be to have an abstract method Load on PhotoBase, that's then implemented by each subclass:
public abstract class PhotoBase
{
public string Path { get; set; }
public abstract void Load();
}
public class FilePhoto : PhotoBase
{
public override void Load()
{
// load from file system
}
}
public class ExternalPhoto : PhotoBase
{
public override void Load()
{
// load from path
}
}
That way, you can simply call the Load method on a PhotoBase:
public class PhotoImporter
{
public void ImportPhoto(PhotoBase photo)
{
photo.Load();
}
}
The main advantage is that each subclass implements the Load method, and therefore you can add as many subclasses as you want, without worrying about forgetting to implement it.
The main drawback to this implementation is that the Load methods can't depend on other dependencies. So for example, if one day you need to load a photo from a database, you can't pass the DBContext.
Proper to way to implement it which will make code easy to maintain is as follows:
public abstract class PhotoBase
{
public string Path { get; set; }
public abstract void Load(); // Have a abtract method
}
public class FilePhoto : PhotoBase {
public override void Load() { // Implement the abtract method
Console.WriteLine("FilePhoto");
}
}
public class ExternalPhoto : PhotoBase {
public override void Load() { // // Implement the abtract method
Console.WriteLine("ExternalPhoto");
}
}
public class PhotoLoader
{
private PhotoBase _PhotoBase;
public PhotoLoader(PhotoBase photoBase) { // Resolved by Dependency Injection
_PhotoBase = photoBase;
}
public void Load()
{
_PhotoBase.Load();
}
}
public class PhotoImporter
{
private PhotoLoader _photoLoader;
public PhotoImporter(PhotoLoader photoLoader) // Resolved by Dependency Injection
{
_photoLoader = photoLoader;
}
public void ImportPhoto()
{
_photoLoader.Load();
}
}
You need to have Dependency Injection define so that specified implementation will get resolved and appropriate 'Load' method will be invoked.
void Main()
{
// Following dependency should be resolved by Dependency Injection
PhotoBase filePhotoBase = new FilePhoto();
PhotoLoader filePhotoLoader = new PhotoLoader(filePhotoBase);
PhotoImporter filePhotoImporter = new PhotoImporter(filePhotoLoader);
PhotoBase externalPhotoBase = new ExternalPhoto();
PhotoLoader externalPhotoLoader = new PhotoLoader(externalPhotoBase);
PhotoImporter externalPhotoImporter = new PhotoImporter(externalPhotoLoader);
filePhotoImporter.ImportPhoto(); // Shows output 'FilePhoto'
externalPhotoImporter.ImportPhoto(); // Shows output 'ExternalPhoto'
}
You can have as much implementation as you want, but you need to have proper instance of PhotoImporter by Dependency Injection. Everything else will work smoothly.
This is how I could do this:
public class PhotoImporter
{
private PhotoLoader _photoLoader;
public PhotoImporter(PhotoLoader photoLoader)
{
_photoLoader = photoLoader;
}
public void ImportPhoto(PhotoBase photo)
{
var childType = photo.GetType();
dynamic childPhoto = Convert.ChangeType(photo, childType);
_photoLoader.Load(childPhoto);
}
}
You can simplify your ImportPhotoby using pattern matching:
public void ImportPhoto(photoBase photo)
{
switch(photo)
{
case FilePhoto filePhoto:
loader.Load(filePhoto);
break;
case ExternalPhoto externalPhoto:
loader.Load(externalPhoto);
break;
}
}
But this is only syntactic sugar and doesn't solve your real problem. What might help is a abstract Load method in your base class:
public abstract class PhotoBase
{
public string Path { get; set; }
public abstract void Load();
}
You have to implement this method in your child classes. If you call the method, the correct implementation will be chosen.
Online demo: https://dotnetfiddle.net/LfkxBQ
I have a number of methods that are called on different 3rd party systems. I now have another 3rd party system that will have the same set of methods actioned against it. If both 3rd party systems are connected I will then call the methods on each object in turn.
Currently I have a class that I pass round that I can call the method once and it checks and then calls it on each system that is enabled, this has an instance of each objects classes, similar to this:
public class AACSCaller
{
3rdPartySystem1 _system1;
3rdPartySystem2 _system2;
public AACSCaller(Settings appSettings)
{
_appSettings = appSettings;
if (appSettings.system1Enabled)
{
_system1 = new 3rdPartySystem1();
}
if (appSettings.system2Enabled)
{
_system2 = new 3rdPartySystem2();
}
}
public void Method1()
{
if (appSettings.system1Enabled)
{
_system1.Method1();
}
if (appSettings.system2Enabled)
{
_system2.Method1();
}
}
public void Method2()
{
if (appSettings.system1Enabled)
{
_system1.Method2();
}
if (appSettings.system2Enabled)
{
_system2.Method2();
}
}
}
Is this sensible, as it does seem there maybe a better way and I may well be connecting additional system at some point.
A possible solution here is to define an interface or base class for 3rdPartySystem1 and 3rdPartySystem2 classes, store instances in a collection and call required methods for every item in collection. If only one system is enabled, you'll have only one item in collection, if both is enabled, you'll call them one by one in loop
public interface IThirdPartySystem
{
void Method1();
void Method2();
}
public class ThirdPartySystem1 : IThirdPartySystem
{
//implementation
}
public class ThirdPartySystem2 : IThirdPartySystem
{
//implementation
}
public class AACSCaller
{
IList<IThirdPartySystem> _systems = new List<IThirdPartySystem>();
public AACSCaller(Settings appSettings)
{
_appSettings = appSettings;
if (appSettings.system1Enabled)
{
_systems.Add(new ThirdPartySystem1());
}
if (appSettings.system2Enabled)
{
_systems.Add(new ThirdPartySystem2());
}
}
public void Method1()
{
foreach (var system in _systems)
system.Method1();
}
public void Method2()
{
foreach (var system in _systems)
system.Method2();
}
}
I suggest you to use interface that have Method1 and Method2 methods and then create to classes System1 and System2 that are implements the interface. Where AACSCaller is create you initialize the correct implementation of the interface and in your methods your just Call to the correct instance method without conditions.
public class AACSCaller
{
IThirdPartySystem ThirdPartySystem;
public AACSCaller(Settings appSettings)
{
_appSettings = appSettings;
ThirdPartySystem = appSettings.system1Enabled ? new ThirdPartySystem1() : new ThirdPartySystem2();
}
public void Method1() => ThirdPartySystem.Method1();
public void Method2() => ThirdPartySystem.Method2();
}
public interface IThirdPartySystem
{
void Method1();
void Method2();
}
public class ThirdPartySystem1 : IThirdPartySystem
{
public void Method1()
{
//code here..
}
public void Method2()
{
//code here..
}
}
public class ThirdPartySystem2 : IThirdPartySystem
{
public void Method1()
{
//code here..
}
public void Method2()
{
//code here..
}
}
Suppose I have a Customer class. A customer can have multiple kinds of loyalty points. For one promotion, the customer may be collecting Rewards. In another, the customer may be collecting Miles. And there is no fixed number of kinds of loyalty points that the Customer is built for. I am sure this is a common use case. Is the decorator pattern a good fit given below sample code?
public interface ICustomer
{
void Display();
}
public class SimpleCustomer : ICustomer
{
public void Display()
{
Console.WriteLine("I am simple customer");
}
}
public abstract class CustomerDecorator : ICustomer
{
protected ICustomer customer;
public CustomerDecorator(ICustomer customer)
{
this.customer = customer ?? throw new ArgumentNullException("customer");
}
public abstract void Display();
}
public class RewardsDecorator : CustomerDecorator
{
private int rewards;
public RewardsDecorator(ICustomer customer, int rewards) : base(customer)
{
this.rewards = rewards;
}
public override void Display()
{
Console.WriteLine("Now I have " + rewards.ToString() + " rewards");
}
}
public class MilesDecorator : CustomerDecorator
{
private int miles;
public MilesDecorator(ICustomer customer, int miles) : base(customer)
{
this.miles = miles;
}
public override void Display()
{
Console.WriteLine("Now I have " + miles.ToString() + " miles");
}
}
Don't think Decorator pattern does what you want it to do. Decorator adds new functionalities on top of the original class. A typical wiki example would say, we can add scroll bar, menu bar, overlays and other UI components on top of canvas. So to make a proper browser window, so you will have:
public class Canvas
public class ScrollableCanvas
public class OverlayedCanvas
etc.
So that we add more functionalities to the original Canvas.
To solve your problem, you should have something like:
public abstract class LoyaltyProgramAccount {...}
public class RewardAccount extends LoyaltyProgramAccount {...}
public class MilesAccount extends LoyaltyProgramAccount {...}
And then add a registery-ish enum:
public enum LoyaltyProgramTypes {
miles,
reward,
}
and then let user be:
public class Customer {
private List<LoyaltyProgramTypes, LoyaltyProgramAccount> accounts;
public void openAccount(LoyaltyProgramTypes type, LoyaltyProgramAccount account) {
accounts.put(type, account);
}
...
}
I do not think that Decorator is the pattern you are looking for.
Besides, your code does not seem to be an implementation of the Decorator pattern. You do not add any functionality to the only function. You just override it. But adding to the existing function is what the Decorator pattern is all about.
My approach would be state / strategy pattern. There are different kinds of rewards. And a customer has one or more of them. These rewards may share a common interface and provide different implementations. The customer (or a subclass or compound object RewardedCustomer) should hold a list or map of these rewards.
I would use the visitor pattern, this is pretty ideal for your situation. This will allow you nicely separate the rewards calculations for you different customer types and run operations against all supported rewards types.
class Program
{
static void Main(string[] args)
{
MilesCustomer customer = new MilesCustomer();
ICustomerVisitor<int> visitor = new MilesCalculation(10);
var miles = customer.Visit(visitor);
visitor = new RewardsCalucation(100);
var rewards = customer.Visit(visitor);
}
}
public interface ICustomerVisitor<T>
{
T Visit(SimpleCustomer cusomter);
T Visit(RewardsCustomer cusomter);
T Visit(MilesCustomer cusomter);
}
public abstract class Customer
{
public Customer()
{
TotalMoneySpent = 10;
}
public int TotalMoneySpent { get; private set; }
public abstract T Visit<T>(ICustomerVisitor<T> visitor);
public virtual void Display()
{
Console.WriteLine("I am simple customer");
}
}
public class RewardsCalucation : ICustomerVisitor<int>
{
private int _rewardsPerDollar;
public RewardsCalucation(int rewardsPerDollar) => _rewardsPerDollar = rewardsPerDollar;
public int Visit(SimpleCustomer cusomter)
{
return 0;
}
public int Visit(RewardsCustomer cusomter)
{
return cusomter.TotalMoneySpent * _rewardsPerDollar;
}
public int Visit(MilesCustomer cusomter)
{
return 0;
}
}
public class MilesCalculation : ICustomerVisitor<int>
{
private int _milesPerDollar;
public MilesCalculation(int milesPerDollar) => _milesPerDollar = milesPerDollar;
public int Visit(SimpleCustomer cusomter)
{
return 0;
}
public int Visit(RewardsCustomer cusomter)
{
return 0;
}
public int Visit(MilesCustomer cusomter)
{
return cusomter.TotalMoneySpent * _milesPerDollar;
}
}
public class SimpleCustomer : Customer
{
public override T Visit<T>(ICustomerVisitor<T> visitor)
{
return visitor.Visit(this);
}
}
public class RewardsCustomer : Customer
{
public override T Visit<T>(ICustomerVisitor<T> visitor)
{
return visitor.Visit(this);
}
}
public class MilesCustomer : Customer
{
public override T Visit<T>(ICustomerVisitor<T> visitor)
{
return visitor.Visit(this);
}
}
I would like to refer to the example that was used before on SO
with the Duck and Electric Duck:
public interface IDuck
{
void Swim();
}
public class Duck : IDuck
{
public void Swim()
{
//do something to swim
}
}
public class ElectricDuck : IDuck
{
public void Swim()
{
if (!IsTurnedOn)
return;
//swim logic
}
public void TurnOn()
{
this.IsTurnedOn = true;
}
public bool IsTurnedOn { get; set; }
}
The original violation for LSP would look like this:
void MakeDuckSwim(IDuck duck)
{
if (duck is ElectricDuck)
((ElectricDuck)duck).TurnOn();
duck.Swim();
}
One solution by the author was to put the Logic inside the electric duck's swim method to turn itself on:
public class ElectricDuck : IDuck
{
public void Swim()
{
if (!IsTurnedOn)
TurnOn();
//swim logic
}
public void TurnOn()
{
this.IsTurnedOn = true;
}
public bool IsTurnedOn { get; set; }
}
I have come across other scenarios where an extended interface can be created that supports some sort of initialization:
public interface IInitializeRequired
{
public void Init();
}
Electric Duck could then be extended with this interface:
public class ElectricDuck : IDuck, IInitializeRequired
{
public void Swim()
{
if (!IsTurnedOn)
return;
//swim logic
}
public void TurnOn()
{
this.IsTurnedOn = true;
}
public bool IsTurnedOn { get; set; }
#region IInitializeRequired Members
public void Init()
{
TurnOn();
}
#endregion
}
EDIT: The reason for the extended interface Is based on the author saying that turning on automatically in the swim method might have other undesired results.
Then the method instead of checking and casting to a specific type can look for an extended interface instead:
void MakeDuckSwim2(IDuck duck)
{
var init = duck as IInitializeRequired;
if (init != null)
{
init.Init();
}
duck.Swim();
}
The fact that i made the initialization concept more abstract then to create an extended interface called IElectricDuck with TurnOn() method, may make this seem that I did the right thing, however the whole Init concept may only exist because of electric duck.
Is this a better way/solution or is this just an LSP violation in disguise.
Thanks
It's an LSP violation in disguise. Your method accepts an IDuck, but it requries verification of the dynamic type (whether the IDuck implements IInitializeRequired or not) to work.
One possibility to fix this would be to accept the fact that some ducks require initialization and redefine the interface:
public interface IDuck
{
void Init();
/// <summary>
/// Swims, if the duck has been initialized or does not require initialization.
/// </summary>
void Swim();
}
Another option is to accept that an uninitialized ElectricDuck is not really a duck; thus, it does not implement IDuck:
public class ElectricDuck
{
public void TurnOn()
{
this.IsTurnedOn = true;
}
public bool IsTurnedOn { get; set; }
public IDuck GetIDuck()
{
if (!IsTurnedOn)
throw new InvalidOperationException();
return new InitializedElectricDuck(); // pass arguments to constructor if required
}
private class InitializedElectricDuck : IDuck
{
public void Swim()
{
// swim logic
}
}
}
I would still consider your final example as an LSP violation because logically you do exactly this. As you said, there is no concept of initialization really, it is just made up as a hack.
Indeed, your MakeDuckSwim method should not know anything about any duck's specifics (whether it should be initialized first, fed with some destination after initialization, etc).
It just has to make the provided duck swim!
It is hard to tell on this example (as it is not real), but looks like somewhere "upper" there is a factory or something that creates you a specific duck.
It it possible that you miss the concept of a factory here?
If there was one, then It should know what duck it is creating exactly so probably it should be responsible to know how to initialize a duck, and the rest of your code just works with IDuck without any "ifs" inside behavioral methods.
Obviously you can introduce the concept of "initialization" straight to IDuck interface. Say, a "normal" duck needs to be fed, an electrical one needs to be turned on, etc :) But it sounds a bit dodgy :)
I think first you need to answer this question about electric ducks - do they turn themselves on automatically when someone asks them to swim? If so, turn them on in the Swim method.
If not, it is the duck's client responsibility for turning it on, and you might as well just throw an InvalidOperationException if the duck can't swim because it's turned off.
public interface ISwimBehavior
{
void Swim();
}
public interface IDuck
{
void ISwimBehavior { get; set; }
}
public class Duck : IDuck
{
ISwimBehavior SwimBehavior { get { return new SwimBehavior(); }; set; }
}
public class ElectricDuck : IDuck
{
ISwimBehavior SwimBehavior { get { return new EletricSwimBehavior(); }; set; }
}
The behaviour classes:
public class SwimBehavior: ISwimBehavior
{
public void Swim()
{
//do something to swim
}
}
public class EletricSwimBehavior: ISwimBehavior
{
public void Swim()
{
if (!IsTurnedOn)
this.TurnOn();
//do something to swim
}
public void TurnOn()
{
this.IsTurnedOn = true;
}
public bool IsTurnedOn { get; set; }
}
Maybe something like this:
public interface IDuck
{
bool CanSwim { get; }
void Swim();
}
public class Duck : IDuck
{
public void Swim()
{
//do something to swim
}
public bool CanSwim { get { return true; } }
}
public class ElectricDuck : IDuck
{
public void Swim()
{
//swim logic
}
public void TurnOn()
{
this.IsTurnedOn = true;
}
public bool IsTurnedOn { get; set; }
public bool CanSwim { get { return IsTurnedOn; } }
}
Client would be changed like:
void MakeDuckSwim(IDuck duck)
{
if (duck.CanSwim)
{
duck.Swim();
}
}
I'm trying out an example of using Domain Events to notify of when something has happened in a system (borrowed from here and here).
I'm really close to getting the code working how I want, however, I've hit a bit of a brick wall. Here is my DomainEvents class:
public static class DomainEvents
{
[ThreadStatic]
private static IList<IEventHandler<IDomainEvent>> Actions;
public static void Register<T>(IEventHandler<T> callback) where T : IDomainEvent
{
if (Actions == null)
{
Actions = new List<IEventHandler<IDomainEvent>>();
}
Actions.Add(callback); // <---- Problem here, since I can't add callback to the collection.
}
public static void ClearCallbacks()
{
Actions = null;
}
public static void Raise<T>(T args) where T : IDomainEvent
{
if (Actions == null)
{
return;
}
foreach (var action in Actions)
{
if (action is IEventHandler<T>)
{
((IEventHandler<T>)action).Handle(args);
}
}
}
The above won't compile because Actions.Add cannot accept callback since it's a IEventHandler<T> type rather then a IEventHandler<IDomainEvent> type. Here's some more code to clarify.
This is called from my console application:
DomainEvents.Register(new CustomerHasUnpaidDuesEventHandler());
CustomerHasUnpaidDuesEventHandler implements IEventHandler<CustomerHasUnpaidDuesEvent>, where CustomerHasUnpaidDuesEvent implements IDomainEvent.
public class CustomerHasUnpaidDuesEventHandler : IEventHandler<CustomerHasUnpaidDuesEvent>
{
public IEmailSender EmailSender { get; set; }
public void Handle(CustomerHasUnpaidDuesEvent #event)
{
this.EmailSender.SendEmail(#event.Customer.EmailAddress);
}
}
public class CustomerHasUnpaidDuesEvent : IDomainEvent
{
public CustomerHasUnpaidDuesEvent(Customer customer)
{
this.Customer = customer;
}
public Customer Customer { get; set; }
}
This is what I don't get - if CustomerHasUnpaidDuesEvent implements IDomainEvent, then why is the call to Actions.Add failing? How can I resolve this?
EDIT:
To make things clearer, here is entire code for my test app:
class Program
{
static void Main()
{
DomainEvents.Register(new CustomerHasUnpaidDuesEventHandler());
var c = new Customer();
c.EmailAddress = "test#dfsdf.com";
c.CheckUnpaidDues();
}
}
public interface IEventHandler<in T> where T : IDomainEvent
{
void Handle(T args);
}
public interface IEmailSender
{
void SendEmail(string emailAddress);
}
public interface IDomainEvent
{
}
public static class DomainEvents
{
[ThreadStatic]
private static IList<IEventHandler<IDomainEvent>> Actions;
public static void Register<T>(IEventHandler<T> callback) where T: IDomainEvent
{
if (Actions == null)
{
Actions = new List<IEventHandler<IDomainEvent>>();
}
Actions.Add(callback);
}
public static void ClearCallbacks()
{
Actions = null;
}
public static void Raise<T>(T args) where T : IDomainEvent
{
if (Actions == null)
{
return;
}
foreach (IEventHandler<T> action in Actions)
{
(action).Handle(args);
}
}
}
public class CustomerHasUnpaidDuesEventHandler : IEventHandler<CustomerHasUnpaidDuesEvent>
{
public IEmailSender EmailSender { get; set; }
public void Handle(CustomerHasUnpaidDuesEvent #event)
{
this.EmailSender.SendEmail(#event.Customer.EmailAddress);
}
}
public class CustomerHasUnpaidDuesEvent : IDomainEvent
{
public CustomerHasUnpaidDuesEvent(Customer customer)
{
this.Customer = customer;
}
public Customer Customer { get; set; }
}
public class Customer
{
public string Name { get; set; }
public string EmailAddress { get; set; }
public bool HasUnpaidDues { get; set; }
public void CheckUnpaidDues()
{
HasUnpaidDues = true;
DomainEvents.Raise(new CustomerHasUnpaidDuesEvent(this));
}
}
Cheers.
Jas.
There is no need for your Register method to be generic:
public static void Register(IEventHandler<IDomainEvent> callback)
{
if (Actions == null)
{
Actions = new List<IEventHandler<IDomainEvent>>();
}
Actions.Add(callback);
}
Edit:
The problem is that in order to have IEventHandler<CustomerHasUnpaidDuesEvent> to be in the list of IEventHandler<IDomainEvent>s, we need T to be a covariant template parameter in IEventHandler<T> (which is declared as IEventHandler<out T>). However in order to allow the function Handle(T arg), we need T to be contravariant. So strictly this way won't work. Imagine: if we really could insert an IEventHandler<CustomerHasUnpaidDuesEvent> into a list of IEventHandler<IDomainEvent>s, than someone might try to call Handle with the argument of some type which derives from IDomainEvent but is not a CustomerHasUnpaidDuesEvent! This should be impossible to do.
The solution is that we don't need the exact type at Register, so we can keep a reference to a generic base interface. The implementation is here: http://ideone.com/9glmQ
Old answer is not valid, kept below for consistency.
Maybe you need to declare IEventHandler to accept T as a covariant type?
interface IEventHandler<in T> where T: IDomainEvent
{
void Handle();
// ...
}
Edit: surely CustomerHasUnpaidDuesEvent is an IDomainEvent, but you need IEventHandler<CustomerHasUnpaidDuesEvent> to be a IEventHandler<IDomainEvent>. This is exactly what covariance does. In order to allow that, your template parameter in IEventhandler must be declared covariant (<in T> instead of just <T>).