使用接口参数

时间:2018-05-02 23:37:08

标签: c# interface abstract-class overloading

我花了一些时间学习"事件采购"工作以及如何在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)
    }
}

我想做的是如果没有实现匹配方法,则阻止使用基本方法i。即

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
        }
    }
    
  3. 我知道我可以用上述任何一种方式来做,但我更感兴趣的是我能想到的是否可能。

1 个答案:

答案 0 :(得分:0)

您可以显式实现接口,这可以防止在具体实例上出现不需要的事件类型:

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());