イントレ
  • 新規
  • ペイント
  • 一覧
  • 管理
  • Home
  • ダウンロード
  • 日記
  • イラスト
  • リンク
  • About
  •  RSS

本文へジャンプ


イントレ。

Tag for "C#"

«Prev || 1 · 2 · 3 · 4 · 5 ·... | | Next»

Google Reader Notifier 改

Googleリーダー用の新着通知アプリ。
こちらのソースコード リビジョン10をベースに使っています。

■ r3 - 認証API仕様変更対応。
20100623-GoogleReaderNotifierMod_r3.zip(32.3KB)バイナリ
20100623-GoogleReaderNotifierMod_r3_src.zip(53.8KB)ソース



↓過去のもの。

■ 初期リリース版。日本サーバーだと認証コケるので改変。
20090308-GoogleReaderNotifier.zip(30.5KB)バイナリ
20090308-GoogleReaderNotifier_src.zip(53.4KB)ソース

■ r2 - 認証API仕様変更対応。
20090408-GoogleReaderNotifierMod_r2.zip(32.1KB)バイナリ
20090408-GoogleReaderNotifierMod_r2_src.zip(53.6KB)ソース

DynamicObjectを使った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 = "ほえー";
		}

	}
}

並列化の罠?

こんな感じのコードを書いてました。

var items = GetItems();
ProcessItems(items);
...

private void ProcessItems(IEnumerable items)
{
  Task.Factory.StartNew(()=>
  {
    var array = items.Where(...).Select(...).ToArray();
    ... arrayをいろいろいじる ...
  });
}

で、ProcessItemsでitemsにアクセスした瞬間にメソッドが終了します。
例外は吐き出されません。
VSでデバッグすると、itemsの値が表示できません。

ガベージコレクトでもされたんでしょうか?
Task使って並列処理をしてるせいもあるんでしょうが、原因が不明・・・。再現性も低いし。
とりあえず、GetItems().ToArray()としてお茶を濁してみたけど、こういうのって厄介なバグになりそうだなぁ。


Full-row Selection TreeView。

以前チャレンジ失敗して放置してたんだけど、ズバリな回答案があった。

Highlight whole TreeViewItem line in WPF

Borderの中にGridを配置してGrid.Marginを調整することで子要素を段落下げしている。
TreeViewItemの親を辿ることで階層の深さを取得、Grid.Marginにコンバータ経由で渡している。

こんなシンプルな解決案があったなんて。・・・無念。

<追記>
・・・って思ったんだけど、DataTemplateと組み合わせると問題発生。
コンバータ経由で階層の深さを取得する際のタイミングの問題で、
TreeViewItem.Itemsに追加→スタイル設定となって欲しいんだけど逆になるっぽい。

TreeViewItem.Parentが変化したら再計算して適用すればいいのですが、
それを検知する方法がない・・・。
困った。
</追記>



そして、日記を更新する癖が完全に抜けてる件。

フィールドとプロパティの読書速度実験。

どっちが早いのか気になったので、ちょっとテストしてみた。
フィールドとプロパティの通常・リフレクション経由の読み書きを100万回行って時間計測。

read-field(normal): 27.3012ms
read-property(normal): 58.4602ms
read-field(reflection): 395.7991ms
write-property(normal): 397.8156ms
write-field(normal): 398.9727ms
write-field(reflection): 1005.3316ms
read-property(reflection): 2019.6969ms
write-property(reflection): 3130.8138ms

やっぱりフィールドへの読み書きは早いですね。
そして、プロパティへのリフレクション経由読み書きは絶望的なほど遅いですね・・・。


ついでにLambdaExpressionのメンバー名取得も計測。
INotifyPropertyChangedのいけてる実装とかでつかってるやつ。

GetName(() => PROPERTY); // == "PROPERTY"
みたいな感じで、ラムダ式で指定したプロパティ名を取得するってコードになります。
VSのリファクタ機能とか使えるので名前変更とか使ってる場所特定とか、文字リテラルを使うよりメリットは多いです。

が。10万回のテストで2019msとハンパなく遅いです。(文字リテラル指定だと2ms程度)
リフレクション絡む部分はコストが高いってことで、使い方をちゃんと考えなければいけないなぁ。


«Prev || 1 · 2 · 3 · 4 · 5 ·... | | Next»

HTML creation time [0.35sec.]
"intre." by MinagiSyu, sense 1999.11.23.
Powered by Nucleus CMS v3.41

Utilities

タグ
ツール | サッカー | PCパーツ | .NET | SAP1x | 園芸 | Windows 7 | ツクールもどき | SAPFx | WPF | ...すべてのタグ
カレンダー
<   2010-09   >
日月火水木金土
   1234
567891011
12131415161718
19202122232425
2627282930  
最近の更新
    2010-08-31
  • [日記] SAPFx 3.1.0.7。
  • [更新履歴] SmartAudioPlayer Fx 3.1.0.7 リリース。
  • 2010-07-30
  • [日記] 久々のSAPFxリリース。
  • [更新履歴] SmartAudioPlayer Fx 3.1.0.6 をリリース。
  • [ダウンロード] SmartAudioPlayer Fx
  • 2010-07-11
  • [日記] WebMatrixが本気過ぎる件。
  • 2010-06-23
  • [日記] Google Reader APIの認証がまた変わった?
Adsense