【问题标题】:C#, use reflection to get each case name in switchC#,使用反射来获取开关中的每个案例名称
【发布时间】:2015-01-01 01:42:21
【问题描述】:

这是一个人为的字符串字面量 switch 语句示例:

static string GetStuff(string key)
{
    switch (key)
    {
        case "thing1": return "oh no";
        case "thing2": return "oh yes";
        case "cat": return "in a hat";
        case "wocket": return "in my pocket";
        case "redFish": return "blue fish";
        case "oneFish": return "two fish";
        default: throw new NotImplementedException("The key '" + key + "'  does not exist, go ask your Dad");
    }
}

你明白了。

我想做的是通过反射打印每个案例的每个文字字符串。

我在反思方面做得还不够,不知道如何直观地做到这一点。老实说,我不确定反射是否可以做这种事情。

可以吗?如果有,怎么做?

【问题讨论】:

  • 反射用于查看对象信息,即类、属性、方法等。这些东西中的代码无法反映。查看访客模式:en.wikipedia.org/wiki/Visitor_pattern
  • 不幸的是,链接的问答在这里没有说明。目前还不清楚您所说的“在编译时初始化”是什么意思,该链接中给出的答案特别指出了我之前提到的内容,即如果您有足够的case 标签(IIRC,阈值是七个或更多) 代码无论如何都会变成字典。您想在这里实现哪些实际字典无法实现的目标?
  • 我不知道这个功能。当时我只是在寻找一个 const Dictionary 。但问题是天气我是否可以通过反射获得这些。这就是我真正需要知道的。我知道字典是要走的路,根据您的建议,我将切换到该机制。
  • 但是“const Dictionary”是什么意思? 具体而言,您希望获得什么?如果您担心运行时初始化开销,那么 switch 语句并不能解决这个问题(大型开关被实现为运行时初始化字典!)。如果您只是不希望任何其他代码能够修改字典,请参阅ReadOnlyDictionary 类

标签: c# .net reflection switch-statement


【解决方案1】:

不,您无法使用反射 API 读取 IL(您正在寻找的内容)。

您可以找到的最接近的是MethodInfo.GetMethodBody (MethodBody class),它将为您提供带有 IL 的字节数组。要获取方法的实现细节,您需要读取 IL 的库,例如 cecil。

string 的switch 是根据选择的数量使用if 或Dictionary 实现的 - 请参阅Are .Net switch statements hashed or indexed?。因此,如果阅读 IL,请考虑到这一点。*

请注意,您应该使用其他一些机制来表示您的数据,而不是尝试从已编译的代码中读取数据。 IE。使用字典来表示 MikeH's answer 建议的选择。

* 由Mad Sorcerer 找到的switch 实现信息。

【讨论】:

  • 这就是我想知道的。我同意另一种方法是存储信息的更好方法。但这不是我要问的。
  • @colepanike 不是最简单的任务。请参阅 this 以查看 IL switch 实现的一些细节。我会使用 Dictionary 而不是解析方法的主体。
【解决方案2】:

如何使用Dictionary

  Dictionary<string, string> dict = new Dictionary<string, string>();
  dict.Add("thing1", "oh no");
  dict.Add("thing2", "oh yes");
  //and on and on

  string GetStuff(string key)
  {
    if (dict.ContainsKey(key))
      return dict[key];
    else
      return null; //or throw exception
  }

对于您的菜单:

 void addToMenu()
 {
   foreach (string key in dict.Keys)
   {
     //add "key" to menu
   }

 }

【讨论】:

  • 您甚至可以使用较短的初始化语法:new Dictionary&lt;string, string&gt; { { "thing1", "oh no" }, { "thing2", "oh yes" } } 和 TryGetValue
  • 我不使用字典的原因是编译时限制。我选择了这种相当丑陋的语法,因为 Dictionary 不能在编译时生成。
  • @colepanike 你能解释一下你的编译时间限制吗?
  • @colepanike 只需将您的字典存储在static 字段中,然后使用初始化语法来初始化它。
  • @colepanike:“编译时约束”是什么意思?您的 switch 语句如何符合“编译时字典”的条件?这不像您可以在编译时执行代码。另外,您是否知道当switch 语句中的case 标签使用string 值时,C# 编译器将代表您将其转换为运行时初始化字典(对于switch 语句不止一些情况...否则switch 被实现为一系列if/else if/else 语句)。
猜你喜欢
  • 2016-06-17
  • 1970-01-01
  • 2012-10-04
  • 2012-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多