1

I have the following code:

public async Task DispatchAsync(NoticeChannelType type, string message)
    {
        switch (type)
        {
            case NoticeChannelType.Email:
                {
                    var email = JsonConvert.DeserializeObject<NoticeEmail>(message);
                    await _channelResolver.ResolveAsync(email);
                }
                break;
            case NoticeChannelType.Pushover:
                {
                    var pushover = JsonConvert.DeserializeObject<NoticePushover>(message);
                    await _channelResolver.ResolveAsync(pushover);
                }
                break;
            default:
                break;
        }
    }

I would like to remove this switch somehow, create and cast the object to the concrete type.

After that the channelResolver.ResolveAsync is implemented as follows:

public async Task ResolveAsync<T>(T channel) where T : INoticeChannel
    {
        if (channel == null)
            throw new ArgumentNullException(nameof(channel),
                $"Channel: '{typeof(T).Name}' cannot be null.");

        var handler = _context.Resolve<INoticeExecutor<T>>();

        await handler.SendAsync(channel);
    }

I was trying to refactor it to something like this:

public async Task DispatchAsync(NoticeChannelType type, string message)
    {
        var channel = _context.ResolveKeyed<INoticeChannel>(type);

        Type myType = Type.GetType(channel.GetType().FullName);

        await _channelResolver.ResolveAsync((INoticeChannel)JsonConvert.DeserializeObject(message, myType));
    }

but after that in the channelResolver.ResolveAsync type T is INoticeChannel and not the concrete type so the _context.Resolve<INoticeExecutor<T>>(); can`t resolve it.

Is this possible to remove this switch and make this code more elegant and easier to maintain?

1 Answer 1

1

You can invoke the ResolveAsync generic method using either reflection or DLR Dynamic Dispatch, although I'm not sure it would make the code more elegant (the former is ugly like any reflection code) and easier to maintain (with both techniques you lose the compile time type safety).

But here you go:

Reflection:

public async Task DispatchAsync(NoticeChannelType type, string message)
{
    var channelType = _context.ResolveKeyed<INoticeChannel>(type).GetType();
    var channel = JsonConvert.DeserializeObject(message, channelType);
    var resolveMethod = _channelResolver.GetType().GetMethod("ResolveAsync")
        .MakeGenericMethod(channelType);
    await (Task)resolveMethod.Invoke(_channelResolver, new object[] { channel });
}

(if ResolveAsync is interface method, replace _channelResolver.GetType() with typeof(IChannelResolver) where IChannelResolver is your interface name)

DLR Dynamic Dispatch:

public async Task DispatchAsync(NoticeChannelType type, string message)
{
    var channelType = _context.ResolveKeyed<INoticeChannel>(type).GetType();
    var channel = JsonConvert.DeserializeObject(message, channelType);
    await (Task)_channelResolver.ResolveAsync((dynamic)channel);
}
Sign up to request clarification or add additional context in comments.

1 Comment

Big thanks, I know that we can't have everything (elegant, easy to maintain etc.) but I hope I can deal with it in this scenario.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.