INotifyPropertyChangedとジェネリクスとリフレクションの相性の悪さ

仕事でちょっとやっていて困ったのでメモ代わりに記録しておく。
INotifyPropertyChangedインターフェイスとジェネリクスとリフレクションの合わせ技を使った時に相性の悪さがあった。
具体的には以下の状態だ。

このインターフェイスがあったとする。
interface IValue
where TValue : struct
{
    TValue Value { get; set; }
}
これを実装するクラスhogeを作成。このプロパティの変更通知のためにINotifyPropertyChangedを実装する。

class hoge
 : INotifyPropertyChanged, 
 , IValue
 , IValue
{
    private int v = 0;

    string IValue.Value
    {
        get { return v.ToString(); }
        set
        {
            if (v.ToString() == value) return;
            v = decimal.Parse(value);
            OnPropertyChanged("Value");
        }
    }

    int IValue.Value
    {
        get { return v; }
        set
        {
            if (v == value) return;
            v = value;
            OnPropertyChanged("Value");
        }
    }

    protected OnPropertyChanged(string name)
    {
        if(this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
}
もうお分かりだと思う。INotifyPropertyChangedで渡されるのがプロパティ名だけというところがネックになる。
インターフェイスの実装は明示的に記述すれば同名のプロパティを保持することが可能になる。 実際にはキャストしないと使用できないのでバッティングされないのだがこれをリフレクションで取得すると被ってしまいエラーとなる。
void hoge_PropertyChanged(PropertyChangedEventArgs e)
{
    var t = hoge.GetType();
    var pi = t.GetProperty(e.PropertyName);    //ここでエラーになる。
    var value = pi.GetValue(hoge, null);
}
 こういう実装の場合の上手い回避方法が見つからない。

  • INotifyPropertyChangedに別のプロパティ名を渡す?
    ⇒オレオレルールすぎて危険すぎる。
  • インターフェイスの同名プロパティの使用を禁止にする?
    ⇒インターフェイスの多重実装時にこの制限は厳しすぎる。
  • リフレクションによる取得を回避する?
    ⇒一番現実的な気がするが、リフレクションを使用しないとなるとINotifyPropertyChangedを受け取る側の設計で想定しておかないとならない。
  • PropertyChangedEventArgsを拡張して値そのものを渡す?
    ⇒これも独自ルールすぎる。
どうしたものか。

コメント

このブログの人気の投稿

カスタムメイド3D2用プラグインを作りました

VyOS 1.1.1とSoftEther VPN Serverで自宅VPN最速設定

プロバイダをオープンサーキットからIIJへ変更