我有以下代码:
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
类型T
中INoticeChannel
而不是具体类型,因此_context.Resolve<INoticeExecutor<T>>();
无法解决此问题。
是否可以删除此开关并使此代码更优雅,更易于维护?
答案 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);
}