是否可以基于枚举输入返回泛型类?

时间:2020-09-17 19:59:47

标签: c# generics enums

我正在编写一个使用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#的内容,或者我的整个概念不好。我认为我处于死胡同,因为我认为我无法从一个方法返回两个单独的强类型类。

是否可以基于枚举输入返回通用模型?

3 个答案:

答案 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> ...这是多余的,不是吗?