【问题标题】:Custom Ternary-esque Operator for Enumerations with Custom Compiler使用自定义编译器进行枚举的自定义三元运算符
【发布时间】:2012-08-10 06:17:56
【问题描述】:

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

我找不到任何东西,所以我提出这个问题......

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

进行以下枚举:

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. 假设我可以创建运算符,我可以使用“?”作为枚举运算符,即使它被标准三元运算用于布尔值?
  3. 我知道我可以去 Google 获取这篇文章,但如果有人对好的编译器创建文章有任何建议,那就太好了。

--编辑--

我只是想把它放在这里...我知道如果这阻止我进行开发是不切实际的...我知道如何通过其他几种方式实现...我想要的有助于理解我实现我所概述的目标的起点...只是为了尝试编写代码并了解更多关于我日常使用的框架的乐趣。

【问题讨论】:

  • 我感觉到你的痛苦。我想念其他语言中的这种简短表达。但我也觉得你的尝试根本不值得,除非你成功了。不要仅仅为了缩短一些表达式而构建这样的运算符,而是要聪明:完全删除“表达式”,因为它是一个 CONSTANT 键值映射,并构建一个字典 key:enum/value:string 并使用它来查找以简单的 result=dict[myenumval] 方式。更容易、更快、更连贯、更容易编辑。干燥。
  • switch 是最接近的,不会给自己带来太多不便。如果您编写自己的编译器,代码可移植性就会被抛在一边,因为没有其他人会拥有您的编译器,并且常规 C# 编译器会显示一堆错误。
  • 好的,我知道你想要娱乐:) 看我的帖子。
  • " 使用新运算符获得更简洁的格式" 将新运算符引入具有编译器“扩展”的成熟语言中永远不会干净或简洁。它只会让其他人无法阅读您的代码。

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


【解决方案1】:

你为什么不想只使用 switch?

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;
}

【讨论】:

  • 显然我可以使用 switch 语句,我很好奇的一些原因是为了 doe 的可读性和减少代码行......最后我对如何实现这一点更加好奇...... . 它是关于更多地了解我如何做这样的事情。您知道我们大多数开发人员的好奇心......我只是想了解如何编写自己的快捷方式
  • @MichaelGearhardt ...显然您不想为此使用 KeyValuePair 或 Dictionary 或 Tuple[] 或其他任何东西..所以只需更新您不想的问题使用任何明显的解决方案并列出它们。
  • @MichaelGearhardt 没关系。没有人知道什么对你来说是显而易见的,什么不是你不说的。
  • 很好的答案,但是对于 devils-advocate 参数(作为对我帖子中关于枚举定义更改的 -1 的回应)我建议您明确定义一个 @ 987654322@ 并且不要使用default,因为对枚举定义的更改同样可能导致“魔法”停止工作。
【解决方案2】:

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

Dictionary<ComTypes,String>

【讨论】:

  • 再说一次,这与其他可能的解决方案无关......我有工作代码,并且可以毫无问题地实现我需要的......这是关于我如何去实现我所布置的在我的问题中。
【解决方案3】:

三元运算符在 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]

【讨论】:

  • -1 用于枚举和标题数组之间的“神奇”连接。
  • 当有人改变 ComTitles 数组的顺序时,他/她必须记住正确的索引以便将它与 ComTypes 枚举一起使用。枚举也是一样的。在这种情况下,这是一种非常糟糕的依赖索引的方法。
  • @BurundukXP,从最佳实践的角度来看,我大多同意;但是,如果枚举和数组被封装在一个类定义中(数组是私有的)和一个处理索引的公共属性,那么这是一个非常有用的方法。
  • 为了逃避魔法,我们在 BCL 中有一个 Dictionary&lt;K,V&gt; 类。为什么要退回到“enum is int”之战?
【解决方案4】:

根据您对其他答案的 cmets,您似乎希望将此作为学习练习,而不是您将在生产代码中使用的东西,因此虽然有几个非常好的答案我会推荐用于任何其他情况,以下是您可以通过自定义编译器执行此操作的几种方法:

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

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

【讨论】:

    【解决方案5】:

    好的,至于如何:我不能给你任何确切的答案,但按照你所说的方式,这种情况几乎是不可能的。

    CODE 编译器是完全.. 嗯.. 密封的。它是单片的,带有一些小的扩展点(请参阅 ExtensionMethods 和 LINQ 子语言)。如果你真的找到了 LINQ 子语言插件是如何附加到编译器的,请给我留言,非常感谢。我对此表示怀疑,我相信 LINQ 语法是硬编码到编译器中的,但也许我错了。

    但如果我没记错的话——那么添加一个运算符是完全不可能的,至少在你看来是这样。当然还有其他方法。

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

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

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

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

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

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

    要记住一件事:您不能覆盖原始文件。这是不明智的,因为这意味着您使用新操作员简要编写的所有内容 - 将在构建时自动扩展和替换 - 永久。 :) 您需要将扩展​​后的文件写入某个临时文件,将该文件添加到构建下的当前临时编译文件集(并删除原始文件,因为不再需要它)。

    您应该注意到,这正是 XAML/RESX/.. 文件和 .g.cs/.resx.cs/... 临时文件所发生的情况。这是因为这是在 VS/MSBuild 系统中处理此类情况的正常方式 :) 如果您不想构建新的语言支持,您可以在您的语言和一些已知语言之间进行翻译,然后将其添加为 预处理 步骤。就是这样。

    【讨论】:

    • 如果您需要更多指针,请进一步询问(我?)。但我相信,只要您搜索有关 MSBuild 和“如何将自定义 MSBuild 任务添加到 .csproj”的主题,您就会找到所需的一切:)
    • 一组很棒的推荐解决方案!
    猜你喜欢
    • 1970-01-01
    • 2015-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-10
    • 2020-02-04
    • 2015-01-15
    相关资源
    最近更新 更多