< January 2009 | February 2009 | March 2009 >

February 25, 2009

ジェネリックの型推論がイマイチいけてない気がする。

class A { }
class B : A { }

class Sample
{
    static void Method1<T> (T obj) where T : A { Method2 (obj); }

    static void Method2 (B obj) { Console.WriteLine ("obj is B"); }

    static void Method2 (A obj) { Console.WriteLine ("obj is A"); }

    static void Main (string [] args)
    {
        var obj = new B ();
        Method1 (obj);
    }
}

上記の実行結果はどうなるでしょうか。

こたえ。

obj is A
続行するには何かキーを押してください . . .


うーん、イマイチ…。

February 19, 2009

メモ: Google マップで緯度経度を入力する

携帯は W42CA を使用してる。アドレス帳に GPS 情報を記録することができる。コイツを活用できないかなぁと。

外出先で記録した地点の詳細情報を表示すると、こんな感じ。

測地系 WGS-84
表示 dms
緯度 +33.52.48.19
経度 +135.28.02.03

緯度と経度は見慣れない表記。+33° 52' 48.19", +135° 28' 2.03" ってこと。とりあえず自宅にもどって PC で場所を表示したい。Google Map でこの場所を表示するには

N33 52 48.19 E135 28 02.03

のように入力すると表示できるようだ。

February 16, 2009

空の IEnumerable<T> を返す

戻り値が IEnumerable<T> 型の関数で、null でなく、空のシーケンスを返す方法がわかりませんでした。
Enumerable.Empty<TResult> メソッドってのがあるんですね !

return Enumerable.Empty<Person> ();

February 12, 2009

明示的に定義されたインターフェース プロパティへのバインディング

バインディング ソースの概要より

バインディングのソース プロパティとして使用するプロパティは、クラスのパブリック プロパティである必要があります。明示的に定義されたインターフェイス プロパティには、基本実装を持たない保護プロパティ、プライベート プロパティ、および仮想プロパティの場合と同様に、バインディングのためにアクセスすることはできません。

あ、ダメなんですね…笑。

Enumerable.Aggregate メソッドのオーバーロードを整理してみたい。

Enumerable.Aggregate メソッド には、オーバーロードが 3 つあって、使いどころが若干違うように思います。

public static TSource Aggregate<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, TSource, TSource> func
)

一番シンプルなやつ。

string[] beans = { "ささげ", "いんげん", "そらまめ", "えんどう", "だいず", };
Console.WriteLine (
    beans.Aggregate ((work, next) => work + "/" + next)
    );

ポイントは、func が実行される回数が、source.Count () - 1 回だということ。上の例では一発目は work が "ささげ"、next が "いんげん" となります。区切り文字を入れて文字列を連結したりするのにぴったり。

public static TAccumulate Aggregate<TSource, TAccumulate>(
    this IEnumerable<TSource> source,
    TAccumulate seed,
    Func<TAccumulate, TSource, TAccumulate> func
)

初期値のあるやつ。

string[] beans = { "ささげ", "いんげん", "そらまめ", "えんどう", "だいず", };
Console.WriteLine (
    beans.Aggregate (0, (work, next) => work += next.Length)
    );

func は source.Count () 回実行されます。例の一発目は work が 0、next が "ささげ" です。全要素に対して同様の評価を行う必要がある場合に向いてると思います。

public static TResult Aggregate<TSource, TAccumulate, TResult>(
    this IEnumerable<TSource> source,
    TAccumulate seed,
    Func<TAccumulate, TSource, TAccumulate> func,
    Func<TAccumulate, TResult> resultSelector
)

初期値があり、さらに結果に対してごにょごにょすることができるやつ。

string[] beans = { "ささげ", "いんげん", "そらまめ", "えんどう", "だいず", };
Console.WriteLine (
    beans.Aggregate (
        new StringBuilder (), (work, next) => work.AppendFormat ("/{0}類", next), builder => builder.ToString ())
    );

初期値のあるやつと同じで、func は source.Count () 回実行されます。例の一発目は work が StringBuilder ("")、next が "ささげ" です。例はちょっとミスってて、区切りのスラッシュが一個余分な感じです。

TODO: 依存関係プロパティ

DependencyObject.GetValue メソッド (System.Windows) DependencyProperty は DependencyObject 以外にじっそうすることは可能か ? 添付プロパティは可能だが、あれは値の保存先が DependencyObject だから。 Dependency.Object.SetValue/Dependency.Object.GetValue は内部的には何をしてるの ? たとえば、それっぽいIなんとか(インターフェース)がないかさがす。

February 5, 2009

System.Type より、型のインスタンスを生成する

System.Type から型のインスタンスを作成する方法があるはずだと思ってましたが、実際に必要になったので探してみました。System.Activator クラスCreateInstance メソッドで、型からインスタンスを作成することができます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CSharpSample
{
    class Sample
    {
        static void Main (string [] args)
        {
            var sample = new Sample ();
            var obj = Activator.CreateInstance (sample.GetType ());
            Console.Write ("{0}\n", obj);
        }
    }
}

実行結果です。

CSharpSample.Sample
続行するには何かキーを押してください . . .

CreateInstance メソッドには、なにやらいっぱいオーバーロードがあります。また読んどくことにします。

February 4, 2009

Word の表を削除する

いまさら何を言ってるんだ、って言われそうですが…。

Word で文書内に作成した表を選択して Delete キーを押下すると、表内の文字データのみが消えて、表自体は残ってしまいます。Delete はメニューでは [編集] → [クリア] に割り当てられており、表の削除はメニューで言うと [罫線] → [削除] → [表] で、こちらにはキーが割り当てられていません。仕様書や取説など、Word を使用する機会は大変多く、いちいちメニューから表を削除するのが面倒で、ずーっと「切り取り」してました。そう、Ctrl + X です。

現在、業務で使用しているのは Word 2000 ですが、表全体を選択した状態で、Delete キーでなく、Backspace キーで削除できることにさっき気付きました。

多分、後継バージョンもですよね ?

ちょう情けないです… orz

February 2, 2009

続:添付プロパティにしちゃえばいいんじゃない ?

添付プロパティにしちゃえばいいんじゃない ?」の続きです。

要するに、SortDescription を設定することで ListView をソートする場合、ヘッダクリックした際にどのプロパティをキーにしてソートすればよいかを保持しておく必要があります。GridViewColumn や GridViewColumnHeader にそれを保持しようとすると「A Sortable GridView (I mean ListView) Control in WPF(翻訳中)」などのように GridViewColumn を継承したクラスを定義したりオオゴトになってしまうのですが、WPF には添付プロパティってものがあるやんって話です。

なので、こんなクラスで。

using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace SampleApp
{
    public class GridViewSortHelper
    {
        protected ListView  listView;
        protected GridViewColumnHeader lastSortedHeader;
        protected ListSortDirection lastSortDirection = ListSortDirection.Ascending;

        /// <summary>
        /// <c>GridViewSortHelper.SortKey</c> 添付プロパティ
        /// </summary>
        /// <value>ソートに使用するキー文字列</value>
        public static readonly DependencyProperty SortKeyProperty =
            DependencyProperty.RegisterAttached ("SortKey", typeof (string), typeof (GridViewSortHelper), new FrameworkPropertyMetadata (""));

        /// <summary>
        /// 要素に <c>GridViewSortHelper.SortKey</c> 添付プロパティを設定します。
        /// </summary>
        /// <param name="element">プロパティ値の書き込み対象の要素。</param>
        /// <param name="value">要素の <c>GridViewSortHelper.SortKey</c> 属性値</param>
        public static void SetSortKey (GridViewColumn element, string value)
        {
            element.SetValue (SortKeyProperty, value);
        }

        /// <summary>
        /// 要素の <c>GridViewSortHelper.SortKey</c> 添付プロパティを取得します
        /// </summary>
        /// <param name="element"> プロパティ値の読み取り元の要素。</param>
        /// <returns>要素の <c>GridViewSortHelper.SortKey</c> 属性値</returns>
        public static string GetSortKey (GridViewColumn element)
        {
            return (string) element.GetValue (SortKeyProperty);
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="listView">ソート対象の ListView</param>
        public GridViewSortHelper (ListView listView)
        {
            this.listView = listView;
        }

        /// <summary>
        /// ヘッダクリック時処理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void OnHeaderClicked (object sender, RoutedEventArgs e)
        {
            var headerClicked = e.OriginalSource as GridViewColumnHeader;
            if (headerClicked != null)
            {
                var direction = ListSortDirection.Ascending;
                if (headerClicked == lastSortedHeader)
                {
                    if (lastSortDirection == ListSortDirection.Ascending)
                    {
                        direction = ListSortDirection.Descending;
                    }
                }
                var key = GetSortKey (headerClicked.Column);

                var dataView = CollectionViewSource.GetDefaultView (this.listView.ItemsSource);
                dataView.SortDescriptions.Clear ();
                var sortDescription = new SortDescription (key, direction);
                dataView.SortDescriptions.Add (sortDescription);
                dataView.Refresh ();

                lastSortedHeader = headerClicked;
                lastSortDirection = direction;
            }
        }
    }
}
続きを読む...