GetValues とGetNamesでenumが持つ全ての値をforeachで取得する場合、どちらが推奨されるのですか？


新人の方に`enum`が持つ全ての値を`foreach`で取得しようとしてたら、  
エラーが出たと質問されました。

[code]

    public enum TopCities
    {
        Tokyo,
    
        Yokohama,
    
        Osaka,
    
        Nagoya,
    
        Sapporo,
    
        Kobe,
    
        Kyoto
    }
    
    #endregion
    
    #region Public Methods and Operators
    
    public void LoopThroughAllTopCities()
    {
        foreach (string city in Enum.GetValues(TopCities))
        {
            ltlResult.Text += city + "\r\n";
        }
    }
    
    #endregion
    
    #region Methods
    
    protected void Page_Load(object sender, EventArgs e)
    {
        LoopThroughAllTopCities();
    }
    
    #endregion
    
[/code]

このエラーが出てコンパイルできないと聞かれました。

> TopCities' is a 'type' but is used like a 'variable'

この場合[`Enum.GetValues`の引数は`System.Type`](http://referencesource.microsoft.com/#mscorlib/system/enum.cs,20fa909ef3233d20,references)なので、`typeof(TopCities)`を渡すべきです。

![画像の説明をここに入力](https://i.stack.imgur.com/dAyQR.png)

[code]

    foreach (var city in Enum.GetValues(typeof(TopCities)))
    
[/code]

もしくは

[code]

    foreach (var city in Enum.GetNames(typeof(TopCities)))
    
[/code]

で都市名の取得もできますと答えました。

`Enum.GetValues`と`Enum.GetNames`の違いは指定した値を持つ指定した列挙体にある定数の名前を取得する代わりに、定数の値の配列を取得することです。

そこで思ったのですが、どのようなの場合にどちらのメソッドが推奨されるのかを聞きたいです。




名称だけでよいのであれば`Enum.GetNames`、数値と名称が必要であれば`Enum.GetValues`、各フィールドでリフレクションを行うのであれば`Type.GetFields`を使用べきかと思います。

質問の例で`Enum.GetValues`を使用すると`Enum.ToString`の呼び出しコストがかかるので`Enum.GetNames`が適切です。しかし

[code]

    public enum TopCities
    {
        [DisplayName("東京")]
        Tokyo,
        [DisplayName("横浜")]
        Yokohama,
    }
    
[/code]

のように属性が適用されていてそれを参照したいのであれば`Type.GetFields`となります。




名称だけでよいのであれば`Enum.GetNames`、数値と名称が必要であれば`Enum.GetValues`、各フィールドでリフレクションを行うのであれば`Type.GetFields`を使用べきかと思います。

質問の例で`Enum.GetValues`を使用すると`Enum.ToString`の呼び出しコストがかかるので`Enum.GetNames`が適切です。しかし

[code]

    public enum TopCities
    {
        [DisplayName("東京")]
        Tokyo,
        [DisplayName("横浜")]
        Yokohama,
    }
    
[/code]

のように属性が適用されていてそれを参照したいのであれば`Type.GetFields`となります。

