foreach loop can not cast type to the interface it implements

c#, covariance, exception

Solution

I solved this by adding another level of indirection. Having followed advice from @PeterDuniho, I broke apart the `INotification<TMessage>` interface in to two separate interfaces. By adding the new `INotificationProcessor` interface, I can change my collection of listeners from an `ISubscription` to an `INotificationProcessor` and then iterate over my collection of listeners as an INotificationProcessor.

public interface ISubscription
{
    void Unsubscribe();
}

public interface INotification<TMessageType> : ISubscription where TMessageType : class, IMessage
{
    void Register(Action<TMessageType, ISubscription> callback);
}

public interface INotificationProcessor
{
    void ProcessMessage(IMessage message);
}

The `INotificationProcessor` implementation, implements both `INotificationProcessor` and `INotification<TMessageType>`. This allows the `Notification` class below to cast the IMessage provided in to the appropriate generic type for publication.

internal class Notification<TMessage> : INotificationProcessor, INotification<TMessage> where TMessage : class, IMessage
{
    private Action<TMessage, ISubscription> callback;

    public void Register(Action<TMessage, ISubscription> callbackMethod)
    {
        this.callback = callbackMethod;
    }

    public void Unsubscribe()
    {
        this.callback = null;
    }

    public void ProcessMessage(IMessage message)
    {
        // I can now cast my IMessage to T internally. This lets
        // subscribers use this and not worry about handling the cast themselves. 
        this.callback(message as TMessage, this);
    }
}

My `NotificationManager` can now hold a collection of `INotificationProcessor` types instead of `ISubscription` and invoke the `ProcessMessage(IMessage)` method regardless if what comes in to it is an `IMessage` or a `ServerMessage`.

public class NotificationManager
{
    private ConcurrentDictionary<Type, List<INotificationProcessor>> listeners =
        new ConcurrentDictionary<Type, List<INotificationProcessor>>();

    public ISubscription Subscribe<TMessageType>(Action<TMessageType, ISubscription> callback) where TMessageType : class, IMessage
    {
        Type messageType = typeof(TMessageType);

        // Create our key if it doesn't exist along with an empty collection as the value.
        if (!listeners.ContainsKey(messageType))
        {
            listeners.TryAdd(messageType, new List<INotificationProcessor>());
        }

        // Add our notification to our listener collection so we can publish to it later, then return it.
        var handler = new Notification<TMessageType>();
        handler.Register(callback);

        List<INotificationProcessor> subscribers = listeners[messageType];
        lock (subscribers)
        {
            subscribers.Add(handler);
        }

        return handler;
    }

    public void Publish<T>(T message) where T : class, IMessage
    {
        Type messageType = message.GetType();
        if (!listeners.ContainsKey(messageType))
        {
            return;
        }

        // Exception is thrown here due to variance issues.
        foreach (INotificationProcessor handler in listeners[messageType])
        {
            handler.ProcessMessage(message);
        }
    }
}

The original app example now works without issue.

class Program
{
    static void Main(string[] args)
    {
        var notificationManager = new NotificationManager();
        ISubscription subscription = notificationManager.Subscribe<ServerMessage>(
            (message, sub) => Console.WriteLine(message.Content));

        notificationManager.Publish(new ServerMessage("This works"));
        IMessage newMessage = MessageFactoryMethod("This works without issue.");
        notificationManager.Publish(newMessage);

        Console.ReadKey();
    }

    private static IMessage MessageFactoryMethod(string content)
    {
        return new ServerMessage(content);
    }
}

Thanks everyone for the help.

Problem

Edited with complete, working, code-example. In my IRC app, the application receives content from an IRC server. The content is sent in to a factory and the factory spits out an `IMessage` object that can be consumed by the presentation layer of the application. The `IMessage` interface and a single implementation is shown below. ``` public interface IMessage { object GetContent(); } public interface IMessage<out TContent> : IMessage where TContent : class { TContent Content { get; } } public class ServerMessage : IMessage<string> { public ServerMessage(string content) { this.Content = content; } public string Content { get; private set; } public object GetContent() { return this.Content; } } ``` To receive the `IMessage` object, the presentation layer subscribes to notifications that are published within my domain layer. The notification system iterates over a collection of subscribers to a specified `IMessage` implementation and fires a callback method to the subscriber. ``` public interface ISubscription { void Unsubscribe(); } public interface INotification<TMessageType> : ISubscription where TMessageType : class, IMessage { void Register(Action<TMessageType, ISubscription> callback); void ProcessMessage(TMessageType message); } internal class Notification<TMessage> : INotification<TMessage> where TMessage : class, IMessage { private Action<TMessage, ISubscription> callback; public void Register(Action<TMessage, ISubscription> callbackMethod) { this.callback = callbackMethod; } public void Unsubscribe() { this.callback = null; } public void ProcessMessage(TMessage message) { this.callback(message, this); } } public class NotificationManager { private ConcurrentDictionary<Type, List<ISubscription>> listeners = new ConcurrentDictionary<Type, List<ISubscription>>(); public ISubscription Subscribe<TMessageType>(Action<TMessageType, ISubscription> callback) where TMessageType : class, IMessage { Type messageType = typeof(TMessageType); // Create our key if it doesn't exist along with an empty collection as the value. if (!listeners.ContainsKey(messageType)) { listeners.TryAdd(messageType, new List<ISubscription>()); } // Add our notification to our listener collection so we can publish to it later, then return it. var handler = new Notification<TMessageType>(); handler.Register(callback); List<ISubscription> subscribers = listeners[messageType]; lock (subscribers) { subscribers.Add(handler); } return handler; } public void Publish<T>(T message) where T : class, IMessage { Type messageType = message.GetType(); if (!listeners.ContainsKey(messageType)) { return; } // Exception is thrown here due to variance issues. foreach (INotification<T> handler in listeners[messageType]) { handler.ProcessMessage(message); } } } ``` In order to demonstrate how the above code works, I have a simple Console application that subscribes to notifications from the above `ServerMessage` type. The console app first publishes by passing the `ServerMessage` object in to the `Publish<T>` method directly. This works without any issues. The 2nd example has the app creating an IMessage instance using a factory method. The IMessage instance is then passed in to the `Publish<T>` method, causing my variance issue to throw an `InvalidCastException`. ``` class Program { static void Main(string[] args) { var notificationManager = new NotificationManager(); ISubscription subscription = notificationManager.Subscribe<ServerMessage>( (message, sub) => Console.WriteLine(message.Content)); notificationManager.Publish(new ServerMessage("This works")); IMessage newMessage = MessageFactoryMethod("This throws exception"); notificationManager.Publish(newMessage); Console.ReadKey(); } private static IMessage MessageFactoryMethod(string content) { return new ServerMessage(content); } } ``` The exception states that I can not cast an `INotification<IMessage>` (what the Publish method is understands the message being published to be) in to an `INotification<ServerMessage>`. I have tried to mark the INotification interface generic as contravariant, like `INotification<in TMessageType>` but can't do that because I'm consuming `TMessageType` as a parameter to the `Register` method's callbacks. Should I split the interface in to two separate interfaces? One that can register and one that can consume? Is that the best alternative? Any additional help on this would be great.

Original source