我有以下界面
public interface IMessageData {}
public interface IMessageSender<T> where T : class, IMessageData, new()
{
Task<T> BuildType();
Task SendMessage(T message);
}
然后是IMessageSender
public abstract class MessageSenderBase<T> : IMessageSender<T> where T : class, IMessageData, new()
{
public MessageSenderBase() {
}
public abstract Task<T> BuildType();
public async Task SendMessage(T message) {
Console.WriteLine($"Sending {JsonConvert.SerializeObject(message)}");
await Task.FromResult(0);
}
}
要使用这些接口,我通常会创建一个MessageData的新实例,并创建一个MessageSenderBase的特定实现,如
public class MessageDataA : IMessageData {
public MessageDataA() {
}
public string Description { get; set; }
}
和
public class ASender : MessageSenderBase<MessageDataA> {
public override async Task<MessageDataA> BuildType() {
MessageDataA result = new MessageDataA() { Description = "description" };
return await Task.FromResult<MessageDataA>(result);
}
}
在运行时我只在配置中有MessageSenderBase
实现的名称,我需要创建这些类的动态实例并调用这两个方法。使用以下代码可以正确实现:
var className = "ASender";
var buildMethodName = "BuildType";
var sendMethodName = "SendMessage";
Assembly assembly = Assembly.GetExecutingAssembly();
var type = assembly.GetType(className);
var instance = Activator.CreateInstance(type);
//invoke build method
var buildMethodInfo = type.GetMethod(buildMethodName);
dynamic buildAwaitable = buildMethodInfo.Invoke(instance, null);
var returnedType = await buildAwaitable;
//invoke send method
var sendMethodInfo = type.GetMethod(sendMethodName);
dynamic sendAwaitable = sendMethodInfo.Invoke(instance, new[] { returnedType });
await sendAwaitable;
我的问题:
var instance = Activator.CreateInstance(type);
转换为更强的类型而不是将其保留为var吗?这样可以避免我使用MethodInfo和Invoke来调用方法。答案 0 :(得分:1)
我可以转换var instance = Activator.CreateInstance(type);更强的类型,而不是将其作为var?这样可以避免我使用MethodInfo和Invoke来调用方法。
var
并不代表无类型。它是右侧表达式的类型。在这种情况下,它是object
,但您可以将其转换为实际预期的类型。但是,在动态场景中,还需要做更多工作(见下文)。
作为进一步的建议是否有任何方法可以使这种设计更加强大?
常见的解决方案是为您描述的情况设置非通用接口。优点是您可以直接调用方法,但您必须依赖object
而不是通过泛型参数T
提供的某些特定类型。
接口的基本合约将如下所示:
public interface IMessageData {}
public interface IMessageSender
{
Task<object> BuildType();
Task SendMessage(object message);
}
public interface IMessageSender<T> : IMessageSender where T : class, IMessageData, new()
{
Task<T> BuildType();
Task SendMessage(T message);
}
在基本实现中,IMessageSender
的显式实现将帮助您从其通用对应物中隐藏弱类型接口。实现只会将调用传递给泛型方法:
public abstract class MessageSenderBase<T> : IMessageSender<T> where T : class, IMessageData, new()
{
public MessageSenderBase() {
}
Task<object> IMessageSender.BuildType() {
T result = await BuildType();
return result;
}
Task IMessageSender.SendMessage(object message) {
return SendMessage((T)message);
}
public abstract Task<T> BuildType();
public async Task SendMessage(T message) {
…
}
}
然后用法比原始代码简单得多:
var className = "ASender";
var buildMethodName = "BuildType";
var sendMethodName = "SendMessage";
Assembly assembly = Assembly.GetExecutingAssembly();
var type = assembly.GetType(className);
IMessageSender instance = (IMessageSender)Activator.CreateInstance(type);
//invoke build method
var result = await instance.BuildType();
//invoke send method
await instance.SendMessage(result);
答案 1 :(得分:1)
您可以通过提供非通用接口完全绕过此问题。仔细观察,您实际上并不需要公开BuildType
方法。
您最终会得到一个公开单个方法的IMessageSender接口:
public interface IMessageSender
{
Task SendMessage();
}
然后抽象类提供BuildType
方法并将所有内容连接在一起:
public abstract class MessageSenderBase<T> : IMessageSender where T : class, IMessageData, new()
{
public MessageSenderBase() {
}
protected abstract Task<T> BuildType();
public async Task SendMessage() {
var message = await BuildType();
Console.WriteLine($"Sending {JsonConvert.SerializeObject(message)}");
await Task.FromResult(0);
}
}