中年プログラマーの息抜き

カシマルです。 最近、新しい土地へ引っ越しをしたのですが、これを機に何か始めたいなと思ってブログをはじめました。気の向くままに更新していきます。

C#拡張メソッドでDataGridViewとEnumを密にする

はじめに

拡張メソッドを定義したいと思います。拡張メソッドというのは言語の型に機能(メソッド)を追加するような感じでしょうか。それでいてプログラミング言語で決まっているルールの範囲内というところが守られます。(難しいことは必要ない)

DataGridViewのCell

dataGridView1[columnIndex, rowIndex] でDataGridViewCellのオブジェクトが取得できますよね。しかし、DataGridViewを利用するときに列番号をEnumで管理したい。仕様変更に強い設計ですね。 そんなときこうなります。dataGridView1[(int)columnEnum, rowIndex]。このキャスト!数か所なら気にならないけど・・・なんかねえ。ということで

DataGridViewCellのための拡張メソッド

例えば下記のような拡張メソッドが容易に考え付きますが、これはコンパイルが通りません。Enum columnEnum を ValueType columnEnum とすれば通りますけど。。

public static DataGridViewCell Cell(this DataGridView self, Enum columnEnum, int rowIndex) {
     return self[(int)columnEnum, rowIndex];
}

Int32のソースコードでGetHashCode()をみてみる

referencesource.microsoft.comオブジェクトの値がそのまま返却されてます。

       public override int GetHashCode() {
            return m_value;
       }

EnumソースコードでGetHashCode()をみてみる

referencesource.microsoft.com

型付けされたクラスのGetHashCode()を呼び出してますね。

        public override unsafe int GetHashCode()
        {
            // Avoid boxing by inlining GetValue()
            // return GetValue().GetHashCode();
 
            fixed (void* pValue = &JitHelpers.GetPinningHelper(this).m_data)
            {
                switch (InternalGetCorElementType())
                {
                    case CorElementType.I1:
                        return (*(sbyte*)pValue).GetHashCode();
                    case CorElementType.U1:
                        return (*(byte*)pValue).GetHashCode();
                    case CorElementType.Boolean:
                        return (*(bool*)pValue).GetHashCode();
                    case CorElementType.I2:
                        return (*(short*)pValue).GetHashCode();
                    case CorElementType.U2:
                        return (*(ushort*)pValue).GetHashCode();
                    case CorElementType.Char:
                        return (*(char*)pValue).GetHashCode();
                    case CorElementType.I4:
                        return (*(int*)pValue).GetHashCode();
                    case CorElementType.U4:
                        return (*(uint*)pValue).GetHashCode();
                    case CorElementType.R4:
                        return (*(float*)pValue).GetHashCode();
                    case CorElementType.I8:
                        return (*(long*)pValue).GetHashCode();
                    case CorElementType.U8:
                        return (*(ulong*)pValue).GetHashCode();
                    case CorElementType.R8:
                        return (*(double*)pValue).GetHashCode();
                    case CorElementType.I:
                        return (*(IntPtr*)pValue).GetHashCode();
                    case CorElementType.U:
                        return (*(UIntPtr*)pValue).GetHashCode();
                    default:
                        Contract.Assert(false, "Invalid primitive type");
                        return 0;
                }
            }
        }

DataGridViewCellのための拡張メソッドはこうですね

EnumがInt32に型付けされていれば、下記のような拡張メソッドで実装が容易になるし、キャストの気持ち悪さから解放されます。。

public static DataGridViewCell Cell(this DataGridView self, Enum columnEnum, int rowIndex) {
     return self[columnEnum.GetHashCode(), rowIndex];
}

まとめ

拡張メソッドは重宝します。… ただ、個人的に単純なstaticな機能で提供されているもの(string.IsNullOrEmpty()など)をわざわざ拡張して実装しなおす必要なないと思っていて、例えば、今回のように実装しなおすとコードが読みやすくなると思えば利用するのはありなのかなと思います。 ほかにもstaticな機能が提供されるが複数の決まりきった引数を省略するためにこんな拡張もあり?

 

public static T ToEnum<T>(this Int32 self) {
     return (T)Enum.ToObject(typeof(T), self);
}


public static string ToName(this Enum self) {
     return Enum.GetName(self.GetType(), self);
}

 

db39