我正在编写一个使用Razor语法填充令牌的小型电子邮件模板引擎。我有几种电子邮件类型:
public enum EmailType { Welcome, Reminder }
这些类型具有相应的模板和模型,例如Welcome
电子邮件具有模板:
<p>Welcome, @Model.Name</p>
和相应的模型:
public class WelcomeModel { public string Name { get; set; } }
现在,我想创建一种方法,该方法将为给定的枚举强制使用正确的模型,我想像这样:
public ITemplate<T> GenerateTemplate(EmailType emailType)
{
switch (emailType)
{
case EmailType.Welcome:
return new EmailTemplate<WelcomeModel>();
case EmailType.Reminder:
return new EmailTemplate<ReminderModel>();
// ...
}
其中EmailTemplate<T> : ITemplate<T>
,所以我可以链接该方法:
engine
.GenerateTemplate(EmailType.Welcome)
.WithModel(new WelcomeModel()) // this knows it wants WelcomeModel
// and should complain with compiler error otherwise
我在这里显示的代码无法编译,因为T
是未知的。但是,无法推断出此T
:
public ITemplate<T> GenerateTemplate<T>(EmailType emailType)
这给我留下了
engine
.GenerateTemplate<WelcomeModel>(EmailType.Welcome)
.WithModel(new WelcomeModel());
那行得通,但是我觉得我正在传递多余的信息-枚举和模型,而您可以相互推论。我不确定我是否缺少C#的内容,或者我的整个概念不好。我认为我处于死胡同,因为我认为我无法从一个方法返回两个单独的强类型类。
是否可以基于枚举输入返回通用模型?
答案 0 :(得分:3)
是否可以基于枚举输入返回泛型类?
不。不会以对呼叫者有用的方式。
您的方法返回ITemplate<T>
。但是T
必须在编译时定义为 something 。您不能将定义推迟到运行时,除非使用后期绑定(即dynamic
)或非类型安全机制(否定了使用泛型的全部要旨)。
可能的话,如果您可以重新构建问题并解释原因,那么您认为调用返回开放通用类型ITemplate<T>
的方法而调用站点不了解类型参数T
的实际含义是合理的,可以找到有用的解决方案。
但是,到目前为止,正如您在问题中所指出的那样,唯一真正的答案是,没有那行不通,并且如果可以的话,也没有任何意义。
答案 1 :(得分:0)
你不可以做这样的事情吗?
Failed to retrieve settings ....
答案 2 :(得分:0)
否,因为C#不支持真正的通用多态性,并且Diamond运算符尚未允许编写:
public Template<> GenerateTemplate(EmailType emailType)
{
switch (emailType)
{
case EmailType.Welcome:
return new EmailTemplate<WelcomeModel>();
case EmailType.Reminder:
return new EmailTemplate<ReminderModel>();
}
}
您唯一可以做的就是通过使用非通用的顶级接口来模拟它,
ITemplate<T> : ITemplate
因此creator方法将返回ITemplate
:
public ITemplate GenerateTemplate(EmailType emailType)
{
switch (emailType)
{
case EmailType.Welcome:
return new EmailTemplate<WelcomeModel>();
case EmailType.Reminder:
return new EmailTemplate<ReminderModel>();
}
}
但是在您的情况下,如果您希望拥有真正的泛型,则需要创建几种方法:
EmailTemplate<WelcomeModel> GenerateWelcomeTemplate()
=> new EmailTemplate<WelcomeModel>();
EmailTemplate<ReminderModel> GenerateReminderTemplate
=> new EmailTemplate<ReminderModel>();
然后,您将在调用它们之前检查枚举。
这样做更符合您的代码:
if ( EmailType.Welcome )
engine.GenerateWelcomeTemplate().WithModel(new WelcomeModel());
这里的代码更干净。
但是我不明白为什么您在创建WithModel(new WelcomeModel())
之后提供EmailTemplate<WelcomeModel>
...这是多余的,不是吗?