じゃんぬのどっとてきすと

雑記とネタと時々プログラミング

ホーム 連絡をする 同期する ( RSS 2.0 ) Login
投稿数  981  : 記事  4  : コメント  23021  : トラックバック  277

ニュース

My Website

初心者向けのサイトです。

C# と VB.NET の入門サイト

最近のできごと

少し前に女のコが生まれました。家事と育児と仕事にと奮起しています。めちゃくちゃかわいいです。あと Blog の更新は全然してませんが、Twitter とかでアホなこと呟いています。見つけることができたら、ぜひフォローしてあげてください。けっこう喜びます。

Sponsored Link1

Sponsored Link2

Archive

書庫

定数をグループ化できる列挙体 (Enum) は大変便利な機構です。ただし、Char 以外の整数型しか扱うことができません。

データベース周りのコードを書いていると、フィールドなどをベタに指定したくない場合があります。このような場合、「文字列 (System.String 型) の列挙体があればなぁ」などと思うことでしょう。実際私も VB6 を触っていた頃、喉から手が出るほど欲しい機構でした。

.NET では、このような場合には「型付データセット (DataSet)」を使います。狭義のデータベースである必要もなく、フィールドが表現できるのであれば使えます。

それでも、列挙体の System.String 型バージョンが使いたくてやまない場合。クラスに公開された定数メンバ フィールドを並べたりするハズです。(C# だと読めない (読まない) 方が多いらしいので、VB で書いてみました)

VB.NET

'/** 全日本グループ クラス */
Public MustInherit Class 全日本グループ
    Public Const みさき       As String = "みさき"
    Public Const つばさ       As String = "つばさ"
    Public Const にゅうが     As String = "ひゅうが"
    Public Const まさお       As String = "まさお"
    Public Const にった       As String = "にった"
    Public Const かずお       As String = "かずお"
    Public Const まつやま     As String = "まつやま"
    Public Const じとう       As String = "じとう"
    Public Const そうだ       As String = "そうだ"
    Public Const いしざき     As String = "いしざき"
    Public Const わかばやし   As String = "わかばやし"
End Class

'/** ドイツグループ クラス */
Public MustInherit Class ドイツグループ
    Public Const シュナイダー As String = "シュナイダー"
    Public Const メッツァ     As String = "メッツァ"
    Public Const マーガス     As String = "マーガス"
    Public Const シェスター   As String = "シェスター"
    Public Const カペロマン   As String = "カペロマン"
    Public Const ポブルセン   As String = "ポブルセン"
    Public Const カルツ       As String = "カルツ"
    Public Const ヘルマー     As String = "ヘルマー"
    Public Const フライハイト As String = "フライハイト"
    Public Const ブリクサ     As String = "ブリクサ"
    Public Const ミューラー   As String = "ミューラー"
End Class

この方法の欠点は、「自分で定義した変数名に、その "変数名と同じ文字列" を自分で格納する必要がある」これに尽きると思います。

これでは、面倒な上に typo (打ち損じ) がないとも限りません。これを、常に正しく自動で格納するにはどうすれば良いのか考えてみました。リフレクションを使ってかなり異端な実装をします。

VB.NET

'/** ここでインスタンス化する */
<Microsoft.VisualBasic.CompilerServices.StandardModule()> _
Public NotInheritable Class 標準モジュール扱いのクラス
    Public Shared ReadOnly 全日本グループ As New JapanGroup()
    Public Shared ReadOnly ドイツグループ As New GermanyGroup()
End Class

'/** BaseFields クラス */
Public MustInherit Class BaseFields
    Public Sub New()
        Dim hType As System.Type = Me.GetType()
        Dim hFieldInfos As System.Reflection.FieldInfo() = hType.GetFields ( _
            System.Reflection.BindingFlags.GetField     Or _
            System.Reflection.BindingFlags.Public       Or _
            System.Reflection.BindingFlags.Instance     Or _
            System.Reflection.bindingflags.DeclaredOnly    _
        )

        For Each aFieldInfo As System.Reflection.FieldInfo In hFieldInfos
            aFieldInfo.SetValue(Me, aFieldInfo.Name)
        Next
    End Sub
End Class

'/** 全日本グループ クラス */
Public NotInheritable Class JapanGroup : Inherits BaseFields
    Public ReadOnly _
        みさき,     _
        つばさ,     _
        にゅうが,   _
        まさお,     _
        にった,     _
        かずお,     _
        まつやま,   _
        じとう,     _
        そうだ,     _
        いしざき,   _
        わかばやし  _
    As String
End Class

'/** ドイツグループ クラス */
Public NotInheritable Class GermanyGroup : Inherits BaseFields
    Public ReadOnly   _
        シュナイダー, _
        メッツァ,     _
        マーガス,     _
        シェスター,   _
        カペロマン,   _
        ポブルセン,   _
        カルツ,       _
        ヘルマー,     _
        フライハイト, _
        ブリクサ,     _
        ミューラー    _
    As String
End Class

この実装ですと、使う直前に必ず「変数名と同じ文字列」が常に正しく格納されます。その代わりインスタンス メンバになってしまうのが玉に瑕です。

初期化を保証しなくて良い、手動で保証するのであれば、静的フィールドを使う方法もあります。詳しくは下記リンク先をご覧ください。

まあ、「こんな方法を取るな」と言われればそれまでですが、定数のように決まりきった値を使いたい、変数名と同じである保証をしたい。という理由があって、DataSet を使わない場面は一応あります。

リンク先のスレッドだと、テーブルおよびインデックスしかサンプルにあがっていないので、DataSet を使うべきという意見が出ていますが、そういう場面でない時、です。テーブルとか関係なく、グループ化された固定文言とでも言うべき (表現が難しい) 場面です。

私の場合は、レポート コンポーネントの動的なヘッダのパターンがあって、その時は、式フィールドを使ったりしたのですが、正直欲しいと思いましたね。

以上、愚かな試みでした... (*_ _)


こんな劣悪な記事を参考にして、損をしている人が出ているようですので、追記します。

当時、タイプセーフな自作 enum を作るという頭がなかったのか、こんなお遊び記事になっていますが、2 つ有効な方法があります。

ひとつは、.NET 標準の enum を使い、カスタム属性で文字列を拡張する方法。拡張メソッドでそれを取得するメソッドを定義すれば汎用的に使えるでしょう。

もうひとつは Java の enum のように自由かつ強力な拡張が可能な以下のような方法です。たとえば、こんな基底クラスを用意して、

VB.NET

Public MustInherit Class CustomEnumBase(Of TKey, TValue)

    Private key As TKey
    Private value As TValue

    Public Sub New(ByVal key As TKey, ByVal value As TValue)
        MyClass.key = key
        MyClass.value = value
    End Sub

    Public Overrides Function ToString() As String
        Return MyClass.value.ToString()
    End Function

End Class

こんな風にメンバを定義します。

VB.NET

Public NotInheritable Class MyCoke
    Inherits CustomEnumBase(Of Integer, String)

    Public Shared ReadOnly Member1 As New MyCoke(1, "Pepsi NEX")
    Public Shared ReadOnly Member2 As New MyCoke(2, "Pepsi Special")

    Public Sub New(ByVal key As Integer, ByVal value As String)
        MyBase.New(key, value)
    End Sub

End Class

こうすれば、通常の enum と同じようなイメージで使用できます。

メンバ同士の比較が必要な場合は (っていうか普通必要ですけど) compare なメソッドを用意して演算子をオーバーロードすると良いでしょう。めんどくさいので書きません。

投稿日時 : 2006年4月4日 11:33

コメント

# re: 文字列の列挙体 2006/04/04 12:02 じゃんぬ
簡単に言えば、
 使うためにはインスタンス化しなくてはならない
->インスタンス化すると基底クラスのデフォルト コンストラクタが実行される
->コンストラクタでリフレクションを使って "変数名" を取得してそのまま格納
とされるので中身も保証されると。

ちなみに、
 Dim hType As System.Type = Me.GetType()
を、
 Dim hType As System.Type = MyClass.GetType()
にすると、Me と MyClass の違いもわかることでしょう。

いや... あのね、ホント空しいので何かそれっぽいこと書いておきたいんですよ。

# re: 文字列の列挙体 2006/04/04 15:29 囚人
>(C# だと読めない (読まない) 方が多いらしいので、VB で書いてみました)

VB だと読みにくい(読まない…ことはないが)。

# re: 文字列の列挙体 2006/04/04 16:03 中博俊
型付データセットを使えばそれでいいこと
というか型付けないデータセットは使えない

# re: 文字列の列挙体 2006/04/04 16:24 じゃんぬ
> VB だと読みにくい(読まない…ことはないが)

えっと、C# で書く場合と考えると問題のない範囲ですw

> 型付データセットを使えばそれでいいこと

これは正味の DataSet の使い方をしないんですけどね。

中身は格納して決めるんじゃなくて、定数のように決まっていて欲しい。
でも定数とは違って、定数名と中身は同一であって欲しいとか。
確かにあると便利な場面はあります。
たとえば、CrystalReports のヘッダ代わりの式フィールドとかね。

# re: 文字列の列挙体 2006/04/06 10:12 某はいくーぬ
System.Enum.GetNames(GetType(列挙体名))

CType(System.Enum.Parse(GetType(列挙体名), 定数名), 列挙体名)
とかはダメ?

# re: 文字列の列挙体 2006/04/06 10:48 じゃんぬ
> とかはダメ?

これだと、DataSet みたいに ほげ.フィールド1 というスタイルで使用できないですね。

まず、Type を渡すのがあまりに面倒です。
ラップするメソッドを書いたとしても定数名は、
String で固定できるものじゃないですね。
列挙体のようにコンパイル解決したいのが狙いですから。

# re: 文字列の列挙体 2006/04/16 12:43 名無し
ブラジルはこうだww

11 ネイ
10 コインブラ
09 カルロス・サンターナ
08 トニーニョ
07 ザガロ
06 サンタマリア
05 ディウセウ
04 アマラウ
03 ドトール
02 ジェトーリオ
01 ゲルティス

# re: 文字列の列挙体 2006/10/27 4:33 BLUEPIXY
ほげ.フィールド1.ToString();//C#
でダメ?

# re: 文字列の列挙体 2006/10/27 8:58 じゃんぬ
>BLUEPIXY さん
経緯はリンク先の方をご覧ください。
ちなみに、Enum->ToString メソッドは推奨されていないです。
(警告が出ます)

# re: 文字列の列挙体 2006/10/27 17:23 BLUEPIXY
リンク先ざっと見ましたけど、どちらかというと、その後の話みたいでもう一つよく見えませんでした。
要らぬちゃちゃを入れて不快に思われたのならすみません。

# re: 文字列の列挙体 2006/10/27 17:26 BLUEPIXY
ちなみに、
csc for .NET 1.1
csc for .NET 2.0
のどちらも警告はでませんでしたが・

# re: 文字列の列挙体 2006/10/27 17:35 BLUEPIXY
また、MSDNのサンプル
Enum, Enum.ToString
で、実際に使っているサンプルがあり、推奨されないとは書いていませんが・

なんか、MSDNのリンクが書けないですね。
コメントの文字数制限かと思って分断して、削って素っ気なくなってしまいました。

# re: 文字列の列挙体 2006/10/27 19:01 じゃんぬ
BLUEPIXY さん、コメントありがとうございます。

> 要らぬちゃちゃを入れて不快に思われたのならすみません。

いえ、不快には全然思っていないです。
文章だとどうも素っ気無く見えてしまうようです。

> どちらも警告はでませんでしたが

Visual Studio 2005 だと、インテリセンス上に、
「使用しないでください」
と表示されたかと思います。

> また、MSDNのサンプル
> Enum, Enum.ToString
> で、実際に使っているサンプルがあり、推奨されないとは書いていませんが・

ここは、ちょっと誤解があるように思えます。
MSDN ライブラリの使用例などのコードは、自動で生成されたものです。
辻褄のあっていないものはたくさんあります。

私も含め、Microsoft MVP な人が、結構フィードバックしていますよ。

# re: 文字列の列挙体 2006/10/28 2:55 BLUEPIXY
>Visual Studio 2005 だと、インテリセンス上に、「使用しないでください」 と表示されたかと思います。
そうですか、「Visual Studio 2005」環境構築していないので気付きませんでした。しかしまあ、変な話ではありますね。
結局の処、インテリセンスが、推奨されないという根拠なワケですね。
1つ賢くなりました。
ご教授ありがとうございました。
m(_ _)m

# re: 文字列の列挙体 2006/10/28 3:23 BLUEPIXY
>MSDN ライブラリの使用例などのコードは、自動で生成されたものです。
>辻褄のあっていないものはたくさんあります。
間違ったコードが書かれていることがあるというのは、わかります。
だけれども、自動で生成されたからと言って、それを理由にすぐさまそんなのは根拠にならないということにはならないと思います。
自動生成ということは、おそらくテストUnit?みたいなことなんでしょうけど、
例えば、Enum クラスのサンプルを見ると、
WriteLine を使ってフィールド名を(暗黙のToStringで)表示していますが、それは、もちろん、自動生成されたからではなくて、そのような意図(フィールド名が文字列要求されたときにはその名前を返すということのテスト)をもってテスト生成されたということですよね。

# re: 文字列の列挙体 2006/10/28 9:20 じゃんぬ
推奨されていない理由は、FlagAttribute 属性関係を危惧してのことだと思います。
通常は (今は) 問題ないのでしょうけど、CLR の実装が変わればできなくなる可能性もあります。
今現在、すでにインテリセンス上では「使用するな」とまで言われているわけですから。

それと、単一で定義されていないものを ToString メソッドで呼び出せてしまう (普通はしませんが) のも、なるべく避けたいですし、何より、列挙体本来の使い方ではないので、わかりにくいですね。
少なくとも、リフレクションを使った方法よりか推奨されないと考えています。

リフレクションを使った方法では、保証があるのとフィールド名までのパスが明確でわかりやすいのが利点なので、(あとは面白そうだったので) こちらの記事では、これのみを紹介しました。

> そのような意図 をもってテスト生成されたということですよね

そのような意図の結果、間違ったコードを書いていることもありますし、その意図 "自体" が間違っていることさえあります。
今回の件も、インテリセンスとの相違で (というか記述がないだけですが) その片鱗を見せているわけで、結局のところ Microsoft 内でも辻褄が合っていないことは多々あります。
COM Interop 関係とファイナライザの記述も、過去に辻褄があっていませんでした。

# re: 文字列の列挙体 2006/11/01 4:13 BLUEPIXY
ToString("G")
は、どうでしょう?
この場合、列挙型エントリを文字列として(表示できる場合には)作成するので、意味としてははっきりしていると思います。
MSDNの"列挙型書式指定文字列"を読んでみて下さい。
この場合、これが、辻褄が合わないなんとかかんとかというなら、このエントリ自体おかしいと思います。

# re: 文字列の列挙体 2006/11/14 17:11 BLUEPIXY
>Microsoft MVP な人が
ちなみに
Microsoft MVP な人「中 博俊」さんも
その著作「実践C++/CLI 極めるための基礎と実用テクニック」という一般向けの本の中でToStringメソッドで列挙体の列挙子を取得できると書いてます。
(ちなみにということで、コレを使えという意味ではありませんし、だからどうということもありません)

# re: 文字列の列挙体 2006/11/23 19:03 BLUEPIXY
>今現在、すでにインテリセンス上では「使用するな」とまで言われているわけですから。
例えば、VC++で、strcpyとかが、strcpy_s を使用するようにとコンパイラで警告がでることを考えると、
コンパイラで警告がでないインテリセンスのメッセージは(辻褄が合わないと言うより)(推奨や警告ではなく)単なるアドバイスに過ぎないと思います。

# re: 文字列の列挙体 2006/11/23 22:00 中博俊
C#のコンパイラはライブラリに基本的に踏み込みませんから、それはちがうでしょう。

# re: 文字列の列挙体 2006/11/25 2:52 BLUEPIXY
そうなんですか、訂正ありがとうございます。

# re: 列挙型を使う(その5) 2007/03/17 11:46 R.Tanaka.Ichiro's Blog
re: 列挙型を使う(その5)

# re: 文字列の列挙体 2007/03/18 9:57 名無し
> Microsoft MVP な人「中 博俊」さんも

とか言ってるけど、Microsoft MVPな人「じゃんぬねっと」さんに対して言う言葉じゃないね。

それと、こちらのサイト(わんくま同盟さん)は、その中博俊さんとじゃんぬねっとさんによって運営されていることをご存知ないのかしら?

よりによって、対抗馬で中博俊さんを出してくること自体がなんだかな。
会話もかみ合ってないし。

BLUEPIXIさんって、OKWebでも何かとずれてると思っていたけど、こんなところでもずれてるんですね。

# 列挙型を使う(その6) 2007/03/19 10:03 R.Tanaka.Ichiro's Blog
列挙型を使う(その6)

# 列挙型を使う(その6) 2007/03/19 10:07 R.Tanaka.Ichiro's Blog
列挙型を使う(その6)

# re: 文字列の列挙体 2007/03/22 20:35 BLUEPIXY
ずれたことを書くのは本意ではないので、一応一連の私の書込について説明しておくと、私の一連の書込は、記事が云々ということではなくて、「ToStringではだめな根拠は何なの?」ということです。
記事と関連性がないずれたコメントだと思われたならすみませんです。
MVPがどうのこうのというのは、知らなくて言ってるのではなくて、MVPが根拠になるの?ということです。
一連の書込は
「推奨されない」根拠がインテリセンスのメッセージによるなら、そういう開発環境を使っていない人はどうしてそれを知ることができるのかという疑問が根底にあります。
やっぱずれてますかねぇf(^_^;

# re: 文字列の列挙体 2007/05/16 21:10 名無し
>MVPがどうのこうのというのは、知らなくて言ってるのではなくて、MVPが根拠になるの?ということです。

じゃあこの書き込みは何?

>Microsoft MVP な人「中 博俊」さんも
>その著作「実践C++/CLI 極めるための基礎と実用テクニック」という一般向けの本の中でToStringメソッドで列挙体の列挙子を取得できると書いてます。

MVPがどうこう関係ないの反論の意味だったらそう書けばいいのに。
問題なのはフィードバックしてるという事実じゃないの?
別にMVPをかばう意図はないけどさ。

# Stringの名前とデフォルト値を持つ定数 2008/07/05 23:39 katamari.wankuma.com
Stringの名前とデフォルト値を持つ定数

# Stringの名前とデフォルト値を持つ定数 2008/07/05 23:43 katamari.wankuma.com
Stringの名前とデフォルト値を持つ定数

# re: 文字列の列挙体 2009/09/20 12:06 no
http://msdn.microsoft.com/ja-jp/library/16c1xs4z%28VS.80%29.aspx

情報が古くなりつつあるため、この記事を補完する情報の掲載を求めます。

# re: 文字列の列挙体 2012/02/10 3:32 みたらし
はじめまして。
古いお話になんですが、Enum.ToString で非推奨なのは Enum.ToString(IFormatProvider) オーバーロードだけではないでしょうか。

このオーバーロードは、MSDNにも「メモ : このメソッドは、互換性のために残されています。」と記載がありますし、
Visual Studio のツールチップにも「使用しないでください/このメソッドのオーバーロードは今後使用しません」と出ます。
が、他のオーバーロードについては、MSDNにも記載がなければ、ツールチップにも警告が出ていません。

インテリセンスの候補リスト上で ToString を選択したときには確かに警告が出ていますが、
これはデフォルトでツールチップに表示されるのが、よりにもよってこのオーバーロードだからなのでは。

…いかがでしょう?(ちょくちょく使うのでダメであってほしくない立場ですw)

# re: 文字列の列挙体 2012/04/20 19:19 renji
みたらしさんに同感です。
・Enum.ToString(IFormatProvider)
・Enum.ToString(string, IFormatProvider)
このインテリセンスに限り[使用しないでください]と表示されていますので、
ほかのケースであれば、良いと考えております。

# re: [WPF][C#]テキストボックスをフォーカスがくると全選択状態にしたい 2016/01/29 16:05 wengdongdong
20161.29wengdongdong
http://www.mymichaelkorssoutlets.org
http://www.mizunorunningshoes.in.net
http://jordan.outletmalls.us.com
http://canadagoose.adsmall.us.com
http://www.basketballshoes.net.co
http://www.louisvuittonoutlets.name
http://www.toms.in.net
http://www.coach-factory-outlet-online.us.com
http://www.hermesuk.org.uk
http://www.kate-spadeoutlet.us
http://www.mcmhandbags.name
http://www.true-religionjeans.net.co
http://www.cheap-uggsonsale.in.net
http://www.nikestoreuk.me.uk
http://www.ralph-lauren.me.uk
http://www.niketrainers.com.co
コメント

# カルティエ マストタンク 2016/11/21 5:50 lsvcbdmrtf@docomo.ne.jp
スーパーは専売店をコピーします
日本の最高級のスーパーマーケットはブランド時計超特便宜通信販売専売店をコピーして、品質よくコピーを表して、2016最も新作、国際ブランドの腕時計はコピーして、業界は唯一ただ2全くありません.世界の1流の高い品質のブランドは時計をコピーして、当店のスーパーは時計専売店をコピーして、以下の世界の1流のブランドを販売して時計をコピーします:ロレックスはコピーして、ウブロはコピーして、オメガはコピーして、シャネルはコピーします...なぜかというと最高な品質のスーパーマーケットはN級の品物をコピーして新作を表して最も商品に新しく着いて、第1を使いを信じて、安心してください、全国の運賃が無料です!
新旧(の程度)の顧客がお願いするのを歓迎します
カルティエ マストタンク http://www.newkakaku.com/gxq2.htm

Post Feedback

タイトル
名前
Url:
コメント: