我想创建一个通用的通知引擎。我们的想法是拥有一个核心引擎来处理任何类型的通知。该引擎将处理通知并处理所有日志记录,错误处理等。
我创建了3个简单的界面:
public interface INotificationInput
{
/// <summary>
/// Friendly Name for logging/tracing usage
/// </summary>
string FriendlyName { get; set; }
string NotificationCode{ get; set; }
Double Version { get; set; }
}
public interface INotificationOutput
{
/// <summary>
/// Friendly Name for logging/tracing usage
/// </summary>
string FriendlyName { get; }
}
public interface INotificationProvider<out Toutput, Tinput> where Toutput : INotificationOutput where Tinput : INotificationInput
{
/// <summary>
/// Friendly Name for logging/tracing usage
/// </summary>
string FriendlyName { get; set; }
/// <summary>
/// Generates and returns an INotificationOutput from data
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
Toutput GenerateNotificationOutput(Tinput data);
}
因此INotificationProvider会将INotificationInput分块以创建INotificationOutput。
这可能是发送电子邮件,短信,您为其命名的信息,引擎将调用方法并执行调度,记录,处理错误等等的魔力。
我实现了这样的界面:
/// <summary>
/// INotificationInput represented by a dummy object
/// </summary>
public class DummyNotificationInput : INotificationInput
{
public string FriendlyName { get; set; }
public string NotificationCode { get; set; }
public double Version { get; set; }
}
public class DummyNotificationOutput : INotificationOutput
{
public string FriendlyName { get; private set; }
}
public class DummyProvider : INotificationProvider<DummyNotificationOutput, DummyNotificationInput>
{
public string FriendlyName { get; set; }
public DummyNotificationOutput GenerateNotificationOutput(DummyNotificationInput data)
{
throw new NotImplementedException();
}
}
现在我希望我的引擎有一个提供者列表:
var providersList = new List<INotificationProvider<INotificationOutput, INotificationInput>>();
问题是我不能做到以下几点:
providersList.Add(new DummyProvider<DummyNotificationOutput, DummyNotificationInput>());
必须有一个解决方案。我使用了错误的方法吗?
答案 0 :(得分:3)
INotificationProvider
的第二个泛型类型参数不具有协变性(在概念层面),但您尝试使用它就像它一样。它实际上是逆变的。
在INotificationProvider
个对象列表中,您已将输入通知定义为INotificationInput
。这意味着添加到此列表中的对象需要能够接受任何类型的INotificationInput
作为其GenerateNotificationOutput
函数的输入。您正在尝试添加仅知道如何处理DummyNotificationInput
个对象的对象。如果传递了其他类型的输入,它将失败。
您的提供商需要接受INotificationInput
个对象,如果您希望能够将其添加到该列表中,或者列表需要将所有对象定义为接受DummyNotificationInput
。
答案 1 :(得分:0)
正如Servy已经回答的那样,由于你providersList
的期待,你无法做到这一点
考虑到这一点,让INotificationProvider
非通用的实际上可能更简单:
public interface INotificationProvider
{
/// <summary>
/// Friendly Name for logging/tracing usage
/// </summary>
string FriendlyName { get; set; }
/// <summary>
/// Generates and returns an INotificationOutput from data
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
INotificationOutput GenerateNotificationOutput(INotificationInput data);
}
然后DummyProvider
变为:
public class DummyProvider : INotificationProvider
{
public string FriendlyName { get; set; }
public INotificationOutput GenerateNotificationOutput(INotificationInput data)
{
throw new NotImplementedException();
}
}
现在,可能不是您的想法 - 您希望将DummyNotificationInput
个实例传递给DummyProvider
您只需输入Provider
代码
public class DummyProvider : INotificationProvider
{
public string FriendlyName { get; set; }
public INotificationOutput GenerateNotificationOutput(INotificationInput data)
{
if (!(data is DummyNotificationInput)) throw new ArgumentException("Invalid type specified", "data");
return something...;
}
}
显然,您丢失了设计时检查 - 但如果您确实需要将它们放在协变列表中,则无法提供具有派生泛型类型参数的实现者