イントレ。
・・・というのを思いついたので実装してみた。
パブリックプロパティと「プロパティ名Changed」という名前のイベントもどきを用意。
こいつにINotifyPropertyChangedを実装して、プロパティへの書き込み時に呼び出してます。
リフレクション経由のプロパティ操作が重いのが難点。
パブリックプロパティと「プロパティ名Changed」という名前のイベントもどきを用意。
こいつにINotifyPropertyChangedを実装して、プロパティへの書き込み時に呼び出してます。
リフレクション経由のプロパティ操作が重いのが難点。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
using System.Linq;
using System.Reflection;
namespace NotifyWrapper_Test
{
public class NotifyWrapper : DynamicObject, INotifyPropertyChanged
{
object obj;
Dictionary<string, Tuple<PropertyInfo, bool>> properties; // <name, <info, has_setter>>
Dictionary<string, EventHandler> events; // <name, delegate>
public event PropertyChangedEventHandler PropertyChanged;
// Tのインスタンスをnew()で作成して使用
public static NotifyWrapper Create<T>() where T : new() { return Create<T>(new T()); }
// Tのインスタンスを指定して使用
public static NotifyWrapper Create<T>(T instance) { return new NotifyWrapper(instance, typeof(T)); }
NotifyWrapper(object instance, Type type)
{
obj = instance;
properties = type.GetProperties()
.ToDictionary(i => i.Name, i => new Tuple<PropertyInfo, bool>(i, i.GetSetMethod() != null));
// プロパティ名Changed という名前のイベントを自動生成
events = properties
.Where(i => i.Value.Item2)
.ToDictionary(i => i.Key + "Changed", i => new EventHandler(delegate { })); // チェック面倒なので空のデリゲートを...
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
Tuple<PropertyInfo, bool> pi;
EventHandler ev;
result =
properties.TryGetValue(binder.Name, out pi) ? pi.Item1.GetValue(obj, null) :
events.TryGetValue(binder.Name, out ev) ? ev :
null;
return (result != null);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
Tuple<PropertyInfo, bool> pi;
if (properties.TryGetValue(binder.Name, out pi))
{
if (pi.Item2 == false)
return false;
pi.Item1.SetValue(obj, value, null);
events[binder.Name + "Changed"](obj, EventArgs.Empty);
if (PropertyChanged != null)
PropertyChanged(obj, new PropertyChangedEventArgs(binder.Name));
return true;
}
var ev = value as EventHandler;
if (ev != null && events.ContainsKey(binder.Name))
{
events[binder.Name] = ev;
return true;
}
return false;
}
// 必須じゃないけどとりあえず
public override IEnumerable<string> GetDynamicMemberNames()
{
return properties.Select(i => i.Key)
.Concat(events.Select(i => i.Key))
.OrderBy(i => i);
}
}
class Foo
{
public string Name { get; set; }
public Foo()
{
Name = "Hoge";
}
}
class Program
{
static void Main(string[] args)
{
dynamic item = NotifyWrapper.Create<Foo>();
// メンバー名を取得してみる
Console.WriteLine("DynamicMembers:");
((NotifyWrapper)item).GetDynamicMemberNames().Run(Console.WriteLine);
// イベント設定
((INotifyPropertyChanged)item).PropertyChanged += (_,e) => Console.WriteLine("PropertyChanged: {0}", e.PropertyName);
var name_changed = new EventHandler((_, __) => Console.WriteLine("Name Changed"));
item.NameChanged += name_changed;
// 読み書きテスト
Console.WriteLine(item.Name); // Hogeのはず
item.Name = "Foo"; // イベントが発動するはず
Console.WriteLine(item.Name); // Fooのはず
// イベント解除してテスト
item.NameChanged -= name_changed;
item.Name = "ほえー";
}
}
}
Loading...
Utilities
- タグ
- カレンダー
- 最近の更新
- Adsense