是否可以更改此代码以便推断通用方法参数?

时间:2012-09-30 22:19:20

标签: c# generics

我为我的WPF应用程序编写了一个简单的介体(它是找到的代码here的衍生物)。

public class Messenger
{
    private IDictionary<Type, IList<MessageObserver>> observers;

    public Messenger()
    {
        observers = new Dictionary<Type, IList<MessageObserver>>();
    }

    public IDisposeObserver AddObserver<TMessageType>(Action<TMessageType> handler) 
        where TMessageType : Message { }

    protected abstract void RemoveObserver<TMessageType>(Action<TMessageType> handler) 
        where TMessageType : Message { }

    public abstract void PostMessage<TMessageType>(TMessageType message) 
        where TMessageType : Message { }
}

Message只是一个空类,它为通过Messenger发布的所有消息提供基类。我们的想法是从这个类派生出来创建一个包含相关数据的特定消息类(有点像EventArgs)。

我的实现方式与我想删除观察者的方式不同。我希望能够以声明的方式指定何时删除它们:

MessengerInstance.AddObserver<LoginMessage>(HandleLogin)
    .RemoveObserverWhen(message => message.LoginResult == LoginResult.Successful);

RemoveObserverWhen方法需要Predicate<T>T应该是AddObserver方法中指定的消息类型。

这里的想法是你可以指定在注册观察者本身的同一位置移除观察者的逻辑。然后,Messenger类将在消息处理程序运行后检查谓词,如果谓词的计算结果为true,则删除消息处理程序和删除处理程序。

每个消息处理程序可以包含任意数量的删除处理程序,因此我将其打包在名为MessageObserver的类中。

public class MessageObserver : IDisposeObserver
{
    private IList<object> disposalHandlers;

    public MessageObserver(object observer)
    {
        Observer = observer;
        disposalHandlers = new List<object>();
    }

    public object Observer { get; private set; }

    public IList<object> DisposalHandlers
    {
        get { return disposalHandlers; }
    }

    public IDisposeObserver RemoveObserverWhen<T>(Predicate<T> predicate) 
        where T : Message
    {
        disposalHandlers.Add(predicate);
        return this;
    }
}

MessageObserver实现IDisposeObserver,提供RemoveObserverWhen方法。

public interface IDisposeObserver
{
    IDisposeObserver RemoveObserverWhen<T>(Predicate<T> predicate) 
        where T : Message;
}

这里的想法是可以返回IDisposeObserver实例,以便可以链接方法。

这一切都有效,我在viewModel中有以下代码:

MessengerInstance.AddObserver<LoginMessage>(HandleLogin)
    .RemoveObserverWhen<LoginMessage>(message => message.LoginResult == LoginResult.Successful)
    .RemoveObserverWhen<LoginMessage>(SecondDisposalHandler);

我遇到的问题是,只有在调用LoginMessage方法时指定泛型参数(在本例中为RemoveObserver)时,这才有效。我希望能够以帖子开头描述的方式调用方法。

我认为我需要以某种方式返回通用IDisposeObserver,但是如果我进行此更改,那么MessageObserver必须是通用的,然后我不能将约束指定为Messenger类是非通用的。

所以我的问题是,我的代码是否可以更新,以便在调用RemoveObserverWhen方法时不必指定消息类型,或者我是否必须使用当前的解决方案?

注意:我知道还有其他可用的实现,但我这样做是为了帮助我理解c#中面向对象的设计原则和泛型,所以请不要指向其他实现的方向。

1 个答案:

答案 0 :(得分:3)

  

我想我需要以某种方式返回一个通用的IDisposeObserver但是如果我进行了这个更改,那么MessageObserver必须是通用的,然后我不能指定约束,因为Messenger类是非泛型的。

您可能希望拥有一个非泛型MessageObserver基类,其中包含所有类型无关的部分,然后是一个实现泛型IDisposeObserver<T>的通用基类。然后,您可以更改AddObserver以返回通用IDisposeObserver<T>,但将字典保留在MessengerIDictionary<Type, IList<MessageObserver>>。所以,要明确,你必须:

public interface IDisposeObserver<T>
{
    IDisposeObserver<T> RemoveObserverWhen(Predicate<T> predicate) 
        where T : Message;
}

public abstract class MessageObserver { ... }

public class MessageObserver<T> : MessageObserver, IDisposeObserver<T> { ... }

当您必须执行 IDiposeObserver<T>.RemoveObserverWhen方法时,问题就出现了 - 您可能需要将字典列表中的每个项目转换为IObserver<T>。那时你就知道T了,而且你知道你已经恰当地填充了这个列表。

当然,如果那是唯一的事情你将会对观察者做什么,你可以改为IDictionary<Type, IList<object>>而不是打扰两个不同的{{1}类。这实际上取决于你是否从非泛型中获得任何价值。