简体   繁体   English

接口上的C#泛型

[英]C# Generics on interface

I'm creating a generic interface to work as command pattern: 我正在创建一个通用接口作为命令模式:

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

Then, I'll have another class that I'll hold a bunch of implementations of this interface (each one with its own type). 然后,我将有另一个类,我将持有这个接口的一堆实现(每个都有自己的类型)。 There I would have a dictionary to put the list of commands to execute like this: 在那里我会有一个字典来放置要执行的命令列表,如下所示:

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

This generates a compilation error because I don't put the type for the IGenericComponent. 这会生成编译错误,因为我没有为IGenericComponent添加类型。 I have a thread that calls the Update method and a method to subscribe (inserta an component to the dictionary): 我有一个调用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);
            }
        }
    }

This code does not compile... I came from Java programming, and in Java I can ommit the parametrized type when I instantiate the type. 这段代码不能编译......我来自Java编程,在Java中我可以在实例化类型时省略参数化类型。 So... I would like to know if is it possible to do that in C# so it would assume that its the generic type (IVisitableObject). 所以...我想知道是否有可能在C#中这样做,所以它会假设它是泛型类型(IVisitableObject)。 Or if you know a better way to solve this problem... The way I've solved this is not the way I would like to use. 或者,如果你知道一个更好的方法来解决这个问题......我解决这个问题的方式并不是我想要使用的方式。 I've removed generics from the interface and used the generic type IVisitableObject as the parameter of Update method. 我已从界面中删除了泛型,并使用泛型类型IVisitableObject作为Update方法的参数。 Thanks in advance. 提前致谢。

The simplest solution is to say 最简单的解决方案就是说

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

I've used the approach in Jason's answer and it works fine, especially if you can hide the cast from IVisitableObject to T in a base class. 我已经在Jason的答案中使用了这种方法并且它工作正常,特别是如果你可以在基类中隐藏从IVisitableObjectT的转换。 But if you want to avoid forcing classes to implement the non-generic interface, you can use this pattern. 但是,如果您想避免强制类实现非泛型接口,则可以使用此模式。 Store your subscribers as a List<object> and use a helper class ( Dispatcher ) to send the message. 将订阅者存储为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