使用自定义编译器进行枚举的自定义三元运算符

时间:2012-08-14 00:26:09

标签: c# asp.net enumeration ternary-operator

我最近发现自己想知道是否存在类似于三元运算符的现有运算符,但是对于枚举....这可能是一个处理工具,用于编写更少的代码来处理枚举值...

我无法找到任何东西,所以我提出了问题......

如何构建自己的运算符来处理枚举,如下所述?

采取以下列举:

public enum ComTypes { Call, Email, SMS } 

假设我需要根据ComType指定弹出对话框的标题。目前我可以像这样使用三元运算符:

ComTypes comType = ...;
var title = comType == ComTypes.Call ? "Make a Call" : 
    comType == ComTypes.Email ? "Send an Email" : 
    /* ComTypes.SMS */ "Send a Text";

我想要的是使用新的枚举运算符来获得更简洁的格式......如下所示:

ComTypes comType = ...;
var title = comType ? 
    .Call: "Make a Call", 
    .Email: "Send an Email", 
    .SMS|default: "Send a Text";

所以我想我的首发问题是:

  1. 我可以创建自定义运算符并与普通C#编译器并行使用吗?
  2. 假设我可以创建运算符,我可以使用“?”作为枚举的运算符,即使它被标准的Ternary Op用于布尔值?
  3. 我知道我可以去谷歌这个,但是如果有人对良好的编译器创建文章有任何建议,那就太棒了。
  4. - 编辑 -

    我只是想在这里搞清楚......我知道如果这阻止我进行开发是不切实际的...我知道如何实现这几个其他方式......我想要什么帮助理解我实现我所概述的内容的一些帮助...仅仅是为了尝试编写代码并更多地了解我日常使用的框架。

5 个答案:

答案 0 :(得分:3)

为什么不想只使用开关?

string title = "";

switch (comType)
{
  case (ComTypes.Call):
    title = "Make a Call";
    break;
  case (ComTypes.Email):
    title = "Send an Email";
    break; 
  case (ComTypes.SMS):
    title = "Send a Text";
    break;
}

答案 1 :(得分:2)

根据您对其他答案的评论,看起来您希望将此作为学习练习,而不是您将在生产代码中使用的内容,因此虽然有几个非常好的答案我会推荐用于任何其他案例,通过自定义编译器可以通过以下几种方式实现:

  • 编写一个运行预构建的应用程序,该应用程序扫描所有C#文件以获取自定义语法,并在将其提供给编译器之前将其替换为switch语句。
  • 使用内置的自定义语法编写自己的完整C#编译器。 (.NET C#编译器不是开源AFAIK)
  • 修改Mono's compiler以包含新语法。这可能是最简单的解决方案,你仍然会学到很多关于如何将C#编译成CIL然后编译JITted。

另请注意,您的语法要求您在词汇流中看得太远,以确定您是在查看三元运算符还是新运算符。

答案 2 :(得分:2)

好的,关于如何:我不能给你任何确切的答案,但这种情况几乎是不可能的,就像你说的那样。

CODE编译器完全......密封。它是单片的,带有一些小的扩展点(参见ExtensionMethods和LINQ sublangauge)。如果您真的发现LINQ子语言插件如何附加到编译器,请给我留言,我很高兴。我对此表示怀疑,我认为LINQ语法是硬编码到编译器中的,但也许我错了。

但如果我没错 - 那么添加一个运算符是完全不可能的,至少在你查看它的方式。当然还有其他方法。

查看XAML或ASPX文件,还是RESX?它们是如何被编译器处理的,嗯?构建项目是一个多步骤的过程。在C#-code-compiling之前解析XAML / ASPX / RESX文件。读取文件后,工具会生成.g.cs /.Designer.cs /aspx.cs/.resx.cs文件,然后将这些文件添加到编译集中,而CAM实际上不会编译XAML / ASPX / RESX编译器。

这是什么意思?这意味着您可以将文件的扩展名更改为.blargh,然后编写一个插件,如XAML / ASPX / RESX解析器/生成器,将.blargh预处理为.cs,瞧。在.blargh你有自己的额外语法好东西,翻译成详细的C#,然后由普通的C#编译器编译。

但请注意,虽然它实际上可以很好地工作,但更改文件扩展名肯定会取消绑定Intellisense和其他csharpy IDE实用程序,我敢打赌你不想几乎从头开始为你的新代码文件扩展重写它们 - 实际上,相当新的语言..

但等等,还有更多,而且更简单!

您甚至不需要.blargh文件类。项目结构基于MSBuild构建系统。在驱动器的某处,有一堆XML脚本描述了构建系统在“解决方案构建”或“项目构建”期间所执行的每一步。它们可编辑,甚至更好,它们可扩展。您可以编写一个插件到构建系统,并将其注入到构建过程的几乎任何现有步骤之间。

想象一下简单性:您编写了一个简单的搜索替换实用程序,它使用您的额外标记加载C#文件,处理它,然后写回“扩展”,转换为普通C#。你可以在“编译”阶段之前注入它,你已经完成了你的问题。

要记住一件事:你不能覆盖ORIGINAL文件。这并不明智,因为这意味着你与新操作员一起简要写下的所有东西 - 将被自动扩展并在构建时被永久地替换。 :)您将要将扩展写入一些临时文件,将该文件添加到构建下的当前临时编译文件集中(并删除原始文件,因为它不再需要)。

您应该注意到这与XAML / RESX / ..文件和.g.cs / .resx.cs / ...临时文件完全相同。这是因为这是在VS / MSBuild系统中处理此类情况的常规方法:)如果您不想构建新的语言支持,则可以在您和某些已知语言之间进行转换,然后将其添加为预处理一步。多数民众赞成。

答案 3 :(得分:1)

在我看来,您希望将枚举用作哈希表。为什么不直接使用哈希表。

Dictionary<ComTypes,String>

答案 4 :(得分:0)

三元运算符不是C#中的可重载运算符。

话虽如此,我建议简明扼要:

public enum ComTypes { Call = 0, Email = 1, SMS = 2 };
public readonly string[] ComTitles = 
     { "Make a Call", "Send an Email", "Send a Text" };

稍后在代码中你可以使用

ComTitles[comType]