根据类型

时间:2017-05-30 17:42:31

标签: c# reflection autofac

我有以下代码:

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;
        }
    }

我想以某种方式删除此开关,创建对象并将其转换为具体类型。

之后,channelResolver.ResolveAsync实现如下:

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);
    }

我试图将它重构为这样的东西:

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));
    }

但之后channelResolver.ResolveAsync类型TINoticeChannel而不是具体类型,因此_context.Resolve<INoticeExecutor<T>>();无法解决此问题。

是否可以删除此开关并使此代码更优雅,更易于维护?

1 个答案:

答案 0 :(得分:1)

你可以使用反射或DLR Dynamic Dispatch调用ResolveAsync泛型方法,虽然我不确定它会使代码更优雅(前者像任何反射代码一样难看)更容易维护(使用这两种技术都会失去编译时类型的安全性)。

但是你走了:

反射:

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 });
}

(如果ResolveAsync是接口方法,请将_channelResolver.GetType()替换为typeof(IChannelResolver),其中IChannelResolver是您的接口名称)

DLR动态调度:

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);
}