C # Generics on Interface

I am creating a common interface to work as a command template:

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

Then I will have another class that I will spend a bunch of implementations of this interface (each with its own type). There I would have a dictionary that would list the list of commands as follows:

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

This creates a compilation error because I did not set the type for IGenericComponent. I have a thread that calls the Update method and a method for subscribing (insert the component into the dictionary):

 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 omit the parameterized type when I instantiate the type. So ... I would like to know if it is possible to do this in C #, so he would suggest that its generic type (IVisitableObject). Or if you know the best way to solve this problem ... I solved it not the way I would like. I removed the generics from the interface and used the generic type IVisitableObject as a parameter to the Update method. Thanks in advance.

+4
source share
2 answers

I used this approach in Jason's answer and it works great, especially if you can hide the cast from IVisitableObject to T in the base class. But if you want to avoid forcing classes to implement a non-generic interface, you can use this template. Save the subscribers as a List<object> and use the helper class ( Dispatcher ) to send the message.

 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); } } } 
+2
source

The simplest solution is to say

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

Source: https://habr.com/ru/post/1390276/


All Articles