【问题标题】:Generate JavaScript Representation of Enums生成枚举的 JavaScript 表示
【发布时间】:2013-05-21 14:24:00
【问题描述】:

我的代码中有几个 [Flags] 枚举,我想在不复制和粘贴的情况下向 JavaScript 公开。 SignalR 似乎通过将 URL 映射到返回由反射生成的 JavaScript 存根的 Action 为他们的 Hub 代理做类似的事情。由于代码是在运行时生成的,因此似乎无法将其包含在 Bundles 中。

作为替代方案,我实现了一个 T4 模板以在设计时生成一个 js 文件:

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="EnvDte" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".js" #>
Enums = {
<#
    var visualStudio = (Host as IServiceProvider).GetService(typeof(EnvDTE.DTE))
                        as EnvDTE.DTE;
    var project = visualStudio.Solution.FindProjectItem(this.Host.TemplateFile)
                                        .ContainingProject as EnvDTE.Project;

    foreach(EnvDTE.ProjectItem item in GetProjectItemsRecursively(project.ProjectItems))
    {
        if (item.FileCodeModel == null) continue;
        foreach(EnvDTE.CodeElement elem in item.FileCodeModel.CodeElements)
        {
            if (elem.Kind == EnvDTE.vsCMElement.vsCMElementNamespace)
            {
                foreach (CodeElement innerElement in elem.Children)
                {
                    if (innerElement.Kind == vsCMElement.vsCMElementEnum)
                    {
                        CodeEnum enu = (CodeEnum)innerElement;
#>  <#= enu.Name #>: {
<#
        Dictionary<string, string> values = new Dictionary<string, string>();
        foreach (CodeElement child in enu.Members)
        {
            CodeVariable value = child as CodeVariable;

            if (value != null) {
                string init = value.InitExpression as string;
                int unused;
                if (!int.TryParse(init, out unused))
                {
                    foreach (KeyValuePair<string, string> entry in values) {
                        init = init.Replace(entry.Key, entry.Value);
                    }
                    init = "(" + init + ")"; 
                }
                values.Add(value.Name, init);
                WriteLine("\t\t" + value.Name + ": " + init + ",");
            }
        }
#>
    },
<#
                    }
                }
            }
        }
    }
#>
};
<#+
  public List<EnvDTE.ProjectItem> GetProjectItemsRecursively(EnvDTE.ProjectItems items)
  {
      var ret = new List<EnvDTE.ProjectItem>();
      if (items == null) return ret;
      foreach(EnvDTE.ProjectItem item in items)
      {
        ret.Add(item);
        ret.AddRange(GetProjectItemsRecursively(item.ProjectItems));
      }
      return ret;
  }
#>

但是,EnvDTE 感觉很脆弱。尤其是处理枚举的逻辑,例如:

[Flags]
public enum Access
{
    None = 0,
    Read = 1,
    Write = 2,

    ReadWrite = Read | Write
}

使用复合值是一种带有字符串替换的肮脏技巧。上面的T4模板会生成:

Enums = {
    Access: {
        None: 0,
        Read: 1,
        Write: 2,
        ReadWrite: (1 | 2),
    },
};

有没有更简洁的方法来实现这一点?理想情况下,通过某种设计时反射来生成 js 文件,以便打包。

【问题讨论】:

    标签: c# asp.net-mvc-4 reflection t4


    【解决方案1】:

    我认为您可以使用 Bundle Transforms 来完成此操作...

    http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification

    您可以定义一个包并附加一个插入源文件内容的 IBundleTransform 类。您应该能够使用反射将 JavaScript 写入输出流。

    如果你想以一种 hacky 的方式来做这件事,这很容易做到。你可以只给它一个空文件并硬编码你的类来使用反射来编写你想要的 JavaScript。

    现在,如果您想以一种不需要修改 IBundleTransform 类来为您的 javascript 输出添加额外枚举的方式来设计它,您需要将一些额外的工作放入一个真实的结构中。例如,假设您将所有枚举放在一个名为 Enums.cs 的文件中,您可以将该文件添加到包的 Include 列表中,您可以动态解析它以获取枚举声明,然后使用反射按名称按顺序查找它们在生成的 JavaScript 文件中输出每一个。

    【讨论】:

      【解决方案2】:

      我喜欢在我的应用程序中使用自定义属性和控制器操作。在开发过程中,我添加了一个枚举值并点击“运行”。我浏览到我的控制器操作(仅在调试期间可用的链接)。控制器抓取我所有实现自定义 [GenerateJavascriptEnum] 属性的枚举,瞧,我看到一个弹出浏览器窗口,其中包含所有漂亮的 javascript。我复制/粘贴并刷新浏览器以获取客户端上的更改。非常舒适,无需大惊小怪。

      【讨论】:

      • 我认为这比我在问题中提到的基于 T4 的方法更糟糕,因为您不仅需要复制和粘贴内容,还必须在浏览器中访问一个神奇的 URL,然后重新编译(!) 复制粘贴后,T4 只需要右键单击->运行自定义工具
      • 不重新编译。只需刷新浏览器即可。没有神奇的 URL,调试时可见的链接。这实际上效果很好,并且受到了我工作过的几个团队的好评。 T4 模板代码往往非常深奥、脆弱且难以维护。我已经使用了这两种方法,并且发现自定义属性解决方案效率更高。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-22
      • 2021-01-04
      • 1970-01-01
      相关资源
      最近更新 更多