繁体   English   中英

接口上的C#泛型

[英]C# Generics on interface

我正在创建一个通用接口作为命令模式:

public interface IGenericComponent<T> where T : IVisitableObject
{
    void Update(T msg);
}

然后,我将有另一个类,我将持有这个接口的一堆实现(每个都有自己的类型)。 在那里我会有一个字典来放置要执行的命令列表,如下所示:

private Dictionary<MessageType, List<IGenericComponent>> _components;

这会生成编译错误,因为我没有为IGenericComponent添加类型。 我有一个调用Update方法的线程和一个订阅方法(将一个组件插入到字典中):

public void Subscribe<T>(MessageType messageType, IGenericComponent<T> component) where T : IVisitableObject, new()
    {
        lock (_monitorDictionary)
        {
            List<IGenericComponent> subscribedList;
            if (_components.TryGetValue(messageType, out subscribedList))
            {
                subscribedList.Add(component);
                IVisitableObject firstUpdate;
                if(_messageBuffer.TryGetValue(messageType, out firstUpdate))
                    component.Update((T)firstUpdate);
            }
            else
            {
                subscribedList = new List<IGenericComponent>();
                subscribedList.Add(component);
                _components[messageType] = subscribedList;
            }
        }
    }

    private void ProcessQueue()
    {
        while (true)
        {
            IVisitableObject msg;
            lock (_monitorQueue)
            {
                msg = _queue.Dequeue();
            }
            List<IGenericComponent> components;
            lock(_monitorDictionary)
            {
                components = _components[msg.MsgType];
            }
            if(components!= null)
            {
                foreach (IGenericComponent genericComponent in components)
                    genericComponent.Update(msg);
            }
        }
    }

这段代码不能编译......我来自Java编程,在Java中我可以在实例化类型时省略参数化类型。 所以...我想知道是否有可能在C#中这样做,所以它会假设它是泛型类型(IVisitableObject)。 或者,如果你知道一个更好的方法来解决这个问题......我解决这个问题的方式并不是我想要使用的方式。 我已从界面中删除了泛型,并使用泛型类型IVisitableObject作为Update方法的参数。 提前致谢。

最简单的解决方案就是说

interface IGenericComponent {
    void Update(IVisitableObject msg);
}
interface IGenericComponent<T> : IGenericComponent where T : IVisitableObject {
    void Update(T msg);
}

我已经在Jason的答案中使用了这种方法并且它工作正常,特别是如果你可以在基类中隐藏从IVisitableObjectT的转换。 但是,如果您想避免强制类实现非泛型接口,则可以使用此模式。 将订阅者存储为List<object>并使用帮助程序类( Dispatcher )发送消息。

public interface IVisitableObject { }
public interface IGenericComponent<T> where T : IVisitableObject
{
    void Update(T msg);
}

abstract class Dispatcher
{
    protected Dispatcher() { }

    public abstract void Dispatch(IVisitableObject message, IEnumerable<object> subscribers);


    static Dictionary<Type, Dispatcher> dispatchers = new Dictionary<Type, Dispatcher>();

    static Dispatcher GetDispatcherFor(IVisitableObject message)
    {
        Type type = message.GetType();

        if (!dispatchers.ContainsKey(type))
        {
            Type closedType = typeof(Dispatcher<>).MakeGenericType(message.GetType());
            object dispatcher = Activator.CreateInstance(closedType);
            dispatchers[type] = (Dispatcher)dispatcher;
        }

        return dispatchers[type];
    }
}

class Dispatcher<T> : Dispatcher where T : IVisitableObject
{
    public override void Dispatch(IVisitableObject message, IEnumerable<object> subscribers)
    {
        var msg = (T)message;
        foreach (var subscriber in subscribers.OfType<IGenericComponent<T>>())
        {
            subscriber.Update(msg);
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM