Указание метода с параметром интерфейса - PullRequest
0 голосов
/ 03 мая 2018

Я потратил некоторое время на изучение того, как работает «Event Sourcing» и как его реализовать в C #, и я застрял в какой-то момент. Поскольку описать мою проблему без кода очень сложно, я сначала дам вам упрощенную версию моего кода. Я удалил весь ненужный код и оставил соответствующие части.

public interface IEvent { }
public class UserCreated : IEvent { }
public class UserDeleted : IEvent { }

public interface IEventSourcable
{
    ICollection<IEvent> History { get; }
    void ApplyEvent(IEvent e);
}

public abstract class EntityBase : IEventSourcable
{
    public ICollection<IEvent> History { get; }
    public void ApplyEvent(IEvent e)
    {
        History.Add(e);
    }
}

public class User : EntityBase
{
    public void ApplyEvent(UserCreated e)
    {
        base.ApplyEvent(e)
    }
}

Что я хотел бы сделать, это запретить использование базового метода, если метод сопоставления не реализован, т.е. е.

User u = new User();
u.ApplyEvent(new UserCreated());

должен работать и вызывать метод в User (что он делает), но

u.ApplyEvent(new UserDeleted()); 

не должен вызывать базовый метод, но выдавать ошибку во время компиляции.

Я видел разные подходы, которые приводили бы к ошибке времени выполнения или просто игнорировали проблему, если не реализован метод сопоставления, такой как

  1. Просто переопределите метод и проверьте тип

    public class User : EntityBase
    {
        public override void ApplyEvent(IEvent e)
        {
            if (e is UserCreated)
                ApplyEvent((UserCreated)e);
            else if (e is UserDeleted)
                ApplyEvent((UserDeleted)e);
            else
                throw new UnknownEventException(); // Or handle it however
        }
    }
    
  2. Использование динамического оператора

    public abstract class EntityBase : IEventSourcable
    {
        public ICollection<IEvent> History { get; }
        public void ApplyEvent(IEvent e)
        {
            History.Add(e);
            ((dynamic)this).Apply((dynamic)e);
        }
    }
    
    public class User : EntityBase
    {
        public override void Apply(UserCreated e)
        {
            // do something
        }
    }
    

Я знаю, что мог бы сделать это любым из упомянутых способов, но меня больше интересует, возможно ли то, о чем я думаю, или нет.

1 Ответ

0 голосов
/ 03 мая 2018

Вы можете явно реализовать интерфейс, что предотвратит нежелательные типы событий в конкретном экземпляре:

public abstract class EntityBase : IEventSourcable
{
    ICollection<IEvent> IEventSourcable.History { get; }

    void IEventSourcable.ApplyEvent(IEvent e)
    {
        // Do the magic
    }

    protected void ApplyEvent(IEvent e)
    {
        (this as IEventSourcable).ApplyEvent(e);
    }
}

public class User : EntityBase
{
    public void ApplyEvent(UserCreated e)
    {
        base.ApplyEvent(e);
    }
}

Однако это не помешает потребителю привести к IEventSourcable и добавить произвольные события:

IEventSourcable u = new User();
u.ApplyEvent(new UserCreated());
u.ApplyEvent(new UserDeleted());
...