月別アーカイブ: 2012年2月

Re:Eric Lippertのクイズ

ネタ元:Eric Lippertのクイズ – 猫とC#について書くmatarilloの雑記

さて、どこにバグがあるでしょうか。

ヒント:ためしに実行してみればわかるかもよ。

ということなので、用意されたIdeoneのページで実行してみた結果、次のようになりました。

 0: 1988
 1: 996
 2: 969
 3: 1050
 4: 980
 5: 1001
 6: 1037
 7: 1031
 8: 1012
 9: 1056

結果を見ると、大体それぞれ1000前後分布していますが、0のところだけ2000前後、つまり倍になっています。

この結果を踏まえてコードをよく見ると、次のところが怪しいですね。

 

// 幅で割って(=幅の逆数を掛けて)整数化。
int index = (int)((datum – min) * multiplier);

 

まず、(datum – min) * multiplierの型はdouble型です。そして、その結果をint型にキャストしています。

double型からint型へのキャストの動作を確認してみましょう。

明示的な数値変換の一覧表 (C# リファレンス)

double 値または float 値を整数型に変換すると、値が切り捨てられます。

「切り捨て」の具体的な動作については記載されていませんが、「0に近い方の整数に丸められる」ということです。つまり、次の値のいずれも、切り捨てられて0になってしまうことになります。

  • 0.1
  • 0.9
  • -0.1
  • -0.9

したがって、「(datum – min) * multiplierの結果が負の1未満の小数である時も、0に分布するとカウントされてしまう」というバグがある、ということになります。

 

この問題を解消するには、例えばMath.Floorメソッドを使い、常に小さい整数に丸めてやるなどの方法があります。

 

int index = (int)Math.Floor((datum – min) * multiplier);

 

今回の例に限らず、明示的なキャストは常に値の精度の変更が伴うので、その挙動を十分に理解したうえで、慎重に使う必要があるということを再確認できた、良い問題でした。

id:matarilloさん、素敵な問題の紹介、ありがとうございました。

Visual Studio用.gitignoreファイル

まあ小ネタです。git init後はまず最初に次のような.gitignoreファイルを作り、Visual Studioが生成するファイル群を除外してします。

 

bin/
obj/
*.user
*.suo
TestResults/

 

検索すればいくらでも引っ掛かるネタではありますが、自分用にメモ。

UTF-8対応版msysGitの問題点

※2012/4/12追記

UTF-8対応版のGitが正式にリリースされ、対応方法を調べてみました。
こちらからどうぞ。
Git-1.7.10-preview20120409.exe のGit Bashで日本語入力する方法

Git日本語対応備忘録 « be free」の記事を書いた直後「msysGit(Git for Windows)がいよいよ公式に UTF-8 をサポート! – てっく煮ブログ」という記事が話題になっていました。

記事で紹介されている「Git-1.7.8-preview20111229-unicode.exe – msysgit – Full installer for unofficial Unicode Git for Windows 1.7.8 – Git for Windows – Google Project Hosting」を使えば確かに日本語ファイル名は文字化けせずに表示されます。

 

UTF-8対応版msysGitの問題

そんなみんなが待ちわびたUTF-8対応版msysGitですが、1つ問題があります。

 

Git Bashで日本語入力できない

Git Bash上で[半角/全角]キーを押して日本語を入力しようとしても、確定前は日本語が表示されるのですが、確定後に数字になってしまいます。

image

image

 

この問題に対処法があれば、ぜひ教えてください。

Visual Studio 11 Betaは2/29リリース

2/29にいよいよ最新バージョンであるVisual Studio 11のBetaがリリースされます。

Visual Studio 11 Beta | Microsoft Visual Studio

 

 

Go Liveライセンス付なので、Betaで作成した製品でも商用利用可能です。

(ただし、製品版リリース後しばらくするとライセンスが切れるので注意)

Go Live | Microsoft Visual Studio

 

Expressエディションは for Windows 8とfor Webだけのようですので、Metro Styleでない従来のデスクトックアプリケーションを作成するにはVS2010 Expressを使えということらしいです。

Express | Microsoft Visual Studio

ADDITIONAL VISUAL STUDIO EXPRESS PRODUCTS

To develop for Windows Phone, or to create desktop applications with Visual C++, Visual C#, or Visual Basic, download a Visual Studio 2010 Express product.

 

やはり新たな製品はワクワクしますね。

座して2/29を待ちたいと思います。

INotifyPropertyChangedを注入する「Notify Property Weaver」

ネタ元:InfoQ: プロパティへのINotifyPropertyChanged注入することができるIL Weaving

 

昨今のデータバインド中心のUI開発では、INotifyPropertyChangedインターフェイスを実装し、プロパティの変更を通知する仕組みが必須です。

しかし、INotifyPropertyChangedインターフェイスの実装は、普通にやるには愚直にそれぞれのプロパティの変更を自前で判断して実装する必要があり、「面倒だ」というのが定説になりつつあります。

 

INotifyPropertyChanged 実装例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace WpfApplication1
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private string myValue;

        public string MyValue
        {
            get { return myValue; }
            set
            {
                if (myValue != value)
                {
                    myValue = value;

                    OnPropertyChanged("MyValue");
                }
            }
        }

        private string myText;

        public string MyText
        {
            get { return myText; }
            set
            {
                if (myText != value)
                {
                    myText = value;

                    OnPropertyChanged("MyText");
                }
            }
        }

        private void OnPropertyChanged(string propertyName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

 

この手間を何とかしようと、多くの人たちが試行錯誤を続けてきました。

ある人はT4テンプレートで自動生成し、ある人はヘルパークラスを作成し、またある人はVS拡張のデザイナーを作ったりしています。

 

そんな中、今回登場したのが「Notify Property Weaver」です。

元記事を読むと、ILを書き換えて変更通知してくれるプロパティに変更してくれるツールのようです。さっそく試してみましょう。

 

まず、VS拡張の導入です。これは、元記事にあるリンクからVS Galleryからvsixをダウンロードしてもいいですし、VSの拡張機能マネージャーから検索すればそこからも導入可能です。

 

導入後、先ほどと同じになるように、ViewModelを次のように作成します。ただし、INotifyPropertyChangedは実装しますが、自動実装プロパティを使用します。

 

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

namespace WpfApplication1
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public string MyValue { get; set; }
        public string MyText { get; set; }
    }
}

 

次に、[プロジェクト]メニュー→[NotifyPropertyWeaver]→[Configure]を選択します。

image

次のダイアログが表示されるので、そのまま[OK]ボタンをクリックします。

image

これで、プロパティの変更通知が自動で行われるようになります。

(ダイアログのなかではいろいろ設定できるようですが、まだよくわからないので今回はスルーします。)

 

それでは、実際に変更通知機構が働くか試してみましょう。

 

MainWindow.xaml、そしてコードビハインドを次のようにします。

 

MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
        Title="MainWindow"
        Width="525"
        Height="350">
    <Grid>
        <StackPanel>
            <TextBlock Text="{Binding MyValue}" />
            <TextBlock Text="{Binding MyText}" />
            <Button Name="MyButton" Content="Press!" Click="MyButton_Click" />
        </StackPanel>
    </Grid>
</Window>

 

MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication1
{
    /// <summary>
    /// MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.DataContext = new MainWindowViewModel();
            InitializeComponent();
        }

        private void MyButton_Click(object sender, RoutedEventArgs e)
        {
            var vm = this.DataContext as MainWindowViewModel;
            vm.MyValue = "hoge!";
            vm.MyText = "fuga!";
        }
    }
}

 

では実行してみます。まずは、次のようにウィンドウが表示されます。

 

image

 

ここで、[Press!]ボタンをクリックすると、コードビハインドのイベントハンドラーでVMに設定した値が画面に表示されます。

 

image

 

無事、変更通知機構が動いているようです。

 

なお、ビルドして生成されたアセンブリをIL Spyでのぞいてみると、次のようになっていました。

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace WpfApplication1
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public string MyValue
        {
            [CompilerGenerated]
            get
            {
                return this.k__BackingField;
            }
            [CompilerGenerated]
            set
            {
                if (string.Equals(this.k__BackingField, value))
                {
                    return;
                }
                this.k__BackingField = value;
                this.OnPropertyChanged("MyValue");
            }
        }
        public string MyText
        {
            [CompilerGenerated]
            get
            {
                return this.k__BackingField;
            }
            [CompilerGenerated]
            set
            {
                if (string.Equals(this.k__BackingField, value))
                {
                    return;
                }
                this.k__BackingField = value;
                this.OnPropertyChanged("MyText");
            }
        }
        public virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
            if (propertyChanged != null)
            {
                propertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

確かに、自動的にILに変更通知機構が追加されていることが確認できます。

 

自動でILを書き換えるため、ビルドに少し時間がかかる感じはしますし、自分で変更通知機構をカスタマイズしたいときにどうするか?などの問題はありますが、ViewModel作成の強い味方になってくれそうですね。

Git日本語対応備忘録

※2012/4/12追記

UTF-8対応版のGitが正式にリリースされたので、この記事の手順は基本的に不要になります。
詳しくはこちらをどうぞ。
Git-1.7.10-preview20120409.exe のGit Bashで日本語入力する方法

久々にGit環境作ったら日本語対応方法を忘れていたので、自分のためにメモ。

Gitのインストール

UTF-8ファイル名対応版 Git for Windowsからダウンロードし、msysGitをインストールします。

まずは日本語を扱えるようにする

Gitのインストールが終わったら、次にGit Bashで日本語が扱えるようにしましょう。

  1. nkfのダウンロード、インストール
    nkf.exe nkf32.dll Windows用の詳細情報 : Vector ソフトを探す!などからnkf.exeをダウンロードし、%ProgramFiles%\Git\binにコピーします。
  2. 日本語対応lessのダウンロード、インストール
    Git付属のlessはUTF-8に対応していないようなので、Windows版less UTF-8対応版バイナリー配布 | twk @ ふらっとなどからUTF-8対応済みのless.exeをダウンロードし、%ProgramFiles%\Git\binに上書きコピーします。
  3. pagerの変更
    %ProgramFiles%\Git\etc\profileファイルを開き、以下の記述を追加します。
    export GIT_PAGER=”nkf -s | LESSCHARSET=utf-8 less”
    以下のコマンドを実行し、pagerを変更します。

    git config --global core.pager "nkf -s | LESSCHARSET=utf-8 less"

    (@bleisさんからTwitterで指摘されたので変更)

  4. git status、git diffで日本語ファイル名が表示されるようにする
    そのままでは日本語ファイル名が”\343\201\246\343\201\231\343\201\250”のような数値コードで表示されてしまいます。以下のコマンドを実行することで、正しく”てすと”と表示されるようになります。

    git config --global core.quotepath false

lsなどのbashコマンドで日本語が扱えるようにする

そのままだと、lsなどのコマンドで表示される日本語ファイル名が化けてしまうので、%ProgramFiles%\Git\etc\profileファイルに、さらに%USERPROFILE%フォルダに”.bashrc”ファイルを作成し、以下の記述を追加します。(@bleisさんからTwitterで指摘されたので変更)

export JLESSCHARSET=japanese-sjis
alias ls='ls --show-control-chars'

なお、”.bashrc”というファイル名は、エクスプローラーのコンテキストメニューの[新規作成]-[テキスト文書]で作成して名前を変えようとしても、

ファイル名先頭のドットや全角空白を含む名前の変更はやり直しできません。

というエラーとなってしまいますので注意が必要です。

一番簡単に作るにはGit Bash上で以下のコマンドを打ちましょう。

cd ~
touch .bashrc

(やはり@bleisさんにTwitterで指摘されたので追記)

エディターの既定のエンコーディングをUTF-8にする

最後に、コミットメッセージをUTF-8で入力するため、使用するエディターの既定のエンコーディングをUTF-8にします。

秀丸を使用するのであれば、次のようなコマンドを打ち、/fu8オプション付きで秀丸を起動するように設定します。

git config --global core.editor "'C:/Program Files/Hidemaru/Hidemaru.exe' //fu8"

課題

  • gitkではUTF-8な日本語が化けてしまう
    • 解決策をご存知の方は教えていただけると助かります<(_ _)>

Molesで基底クラスのpublicメソッドの動作を挿げ替える方法

Moles便利ですよね、Moles。皆さん使ってますか?

そんなMolesを使った小ネタを一つ。

 

対象クラス

image

public class MyBase
{
  public string GetHoge()
  {
    return "hoge";
  }
}

public class MyClass : MyBase
{
  public String GetHogeImpl()
  {
    return base.GetHoge();
  }
}

 

派生クラスのメソッドの中で、基底クラスのメソッドを呼ぶパターンです。

このとき、派生クラスのメソッドをテストするのに、基底クラスのメソッドをモックにしたいというようなケースは、割とあると思います。

(このような設計が良いか悪いかは一家言ある方も多いと思いますが、そこは今回は無視するということで一つよろしくお願いします。)

 

Molesを使った解決法

MolesのStubクラスでは基底クラスのメソッドを挿げ替えることはできないため、ちょっとした工夫が要ります。

そこで、基底クラスのMolesクラスを使うことで、この問題を解決できます。

Molesクラスを使う場合、対象となるインスタンスによって、主に次の2つの方法があります。

 

1.全てのインスタンスで処理をモックにしたいケース

基底クラスのMolesクラスのAllInstancesプロパティにて、処理を挿げ替えます。

[TestMethod]
[HostType("Moles")]
public void TestMethod1()
{
  MMyBase.AllInstances.GetHoge = (myBase) => "fuga";

  var a = new MyClass();
  a.GetHogeImpl().Is("fuga"); // Success

  var b = new MyClass();
  b.GetHogeImpl().Is("fuga"); // Success
}

 

2.一部のインスタンスで処理をモックにしたいケース

基底クラスのMolesクラスのコストラクタ引数に、対象となる派生クラスのインスタンスを渡し、そのインスタンスに対する処理を挿げ替えます。

[TestMethod]
[HostType("Moles")]
public void TestMethod1()
{
  var a = new MyClass();
  new MMyBase(a).GetHoge = () => "fuga";
  a.GetHogeImpl().Is("fuga"); // Success

  var b = new MyClass();
  b.GetHogeImpl().Is("hoge"); // Success
}

 

まとめ

Molesかわいいよ、Moles。

「実例で学ぶASP.NET Webフォーム業務アプリケーション開発のポイント 第1回 3層データバインドを正しく活用しよう(前編)」が公開されました

昨年末くらいから書き始めていた記事が、この度CodeZine様にて公開されました。

3層データバインドを正しく活用しよう(前編)(1/5):CodeZine

まずは無事公開されてホッとしたところです。

記事へのツッコミは、このエントリのコメント欄やtwitter、facebookなど何でも構いませんので、お気軽にお寄せ下さい。

この連載は今後毎月1度公開されていく予定ですので、今後ともよろしくお願いします。

Quick Test Switcher – テストコードと実装コードの切り替えをショートカットキーで一発で行う

テストコードと実装コードの切り替えといえば、JavaならEclipseに「Quick JUnit Plugin」という便利なプラグインがあります。

 

Visual Studioでもそんなのないのかなーと思っていたら、われらが@bleisさんが作ってくれました!

 

Quick Test Switcher 1.1 をリリースした – 予定は未定Blog版

コードを開いた状態で Ctrl-0 を押すと、対応するファイルがある場合にそれを開きます。

頻繁にテストコードと実装コードを切り替える TDD のお供にどうぞ。

 

まだ、テストを実行する力はないみたいですが、この辺はMSTestならCtrl+R,Tというショートカットキーがあるので無問題!

テストコードと実装コードの行き来はTDDやってると頻繁に行う作業ですので、こういった拡張でハードルを下げるのは大事ですよね。

 

というわけで、とっても便利ですので、みんなそっこーで入れるのだ!

(Expressな人はごめんなさい)

DynamicFixedRecord – 固定長文字列を長さで区切って各項目に分割してdynamicにアクセス

ネタ元:neue cc – dynamicとQueryString、或いは無限に不確定なオプション引数について

 

まとめ

dynamicはC#と外の世界を繋ぐためのもの。今日もまた一つ繋いでしまった。それはともかくとして、一番最初、DynamicJsonを実装した頃にも言ったのですが、dynamicはDSL的な側面もあって、普通に楽しめますので、ちょっと頭をひねって活用してみると、また一つ、素敵な世界が待っています。

というわけで、何かやってみようと思っていたところ、twitter上で@kazukさんがこんなことをつぶやいていました。

固定長レコードってのも、C#とは相性が良くないほうのものなので、コネコネしてみました。

  1. using System;
  2. using System.Collections.Specialized;
  3. using System.Dynamic;
  4. using System.Linq;
  5.  
  6. namespace DynamicFixedRecord
  7. {
  8.   public static class StringExtensions
  9.   {
  10.     public static dynamic AsDynamic(this string fixedRecord)
  11.     {
  12.       return new DynamicFixedRecord(fixedRecord);
  13.     }
  14.   }
  15.  
  16.   public class DynamicFixedRecord : DynamicObject
  17.   {
  18.     private NameValueCollection source;
  19.     private string fixedRecord;
  20.  
  21.     public DynamicFixedRecord(string fixedRecord)
  22.     {
  23.       this.source = new NameValueCollection();
  24.       this.fixedRecord = fixedRecord;
  25.     }
  26.  
  27.     public override bool TryGetMember(GetMemberBinder binder, out object result)
  28.     {
  29.       var value = source[binder.Name];
  30.       result = new StringMember(value);
  31.       return true;
  32.     }
  33.  
  34.     public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
  35.     {
  36.       var startIndex = 0;
  37.       source.Clear();
  38.       foreach (var item in binder.CallInfo.ArgumentNames.Zip(args, (key, value) => new { key, value }))
  39.       {
  40.         var length = Int32.Parse(item.value.ToString());
  41.         source.Add(item.key, fixedRecord.Substring(startIndex, length));
  42.         startIndex += length;
  43.       }
  44.  
  45.       result = this;
  46.       return true;
  47.     }
  48.  
  49.     public override bool TryConvert(ConvertBinder binder, out object result)
  50.     {
  51.       if (binder.Type != typeof(string))
  52.       {
  53.         result = null;
  54.         return false;
  55.       }
  56.       else
  57.       {
  58.         result = this.ToString();
  59.         return true;
  60.       }
  61.     }
  62.  
  63.     public override string ToString()
  64.     {
  65.       return string.Join(", ",
  66.         source.Cast<string>().Select(key => key + ":" + source[key]));
  67.     }
  68.   }
  69.  
  70.   class StringMember : DynamicObject
  71.   {
  72.     readonly string value;
  73.  
  74.     public StringMember(string value)
  75.     {
  76.       this.value = value;
  77.     }
  78.  
  79.     public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
  80.     {
  81.       var defaultValue = args.First();
  82.  
  83.       try
  84.       {
  85.         result = (value == null)
  86.             ? defaultValue
  87.             : Convert.ChangeType(value, defaultValue.GetType());
  88.       }
  89.       catch (FormatException)
  90.       {
  91.         result = defaultValue;
  92.       }
  93.  
  94.       return true;
  95.     }
  96.  
  97.     public override bool TryConvert(ConvertBinder binder, out object result)
  98.     {
  99.       try
  100.       {
  101.         var type = (binder.Type.IsGenericType
  102.           && binder.Type.GetGenericTypeDefinition() == typeof(Nullable<>))
  103.             ? binder.Type.GetGenericArguments().First()
  104.             : binder.Type;
  105.  
  106.         result = (value == null)
  107.             ? null
  108.             : type == typeof(DateTime)
  109.               ? DateTime.ParseExact(value,
  110.                 new[] { "yyyyMMdd", "yyyy/MM/dd", "yyMMdd", "yy/MM/dd" },
  111.                 null,
  112.                 System.Globalization.DateTimeStyles.None)
  113.               : Convert.ChangeType(value, binder.Type);
  114.       }
  115.       catch (FormatException)
  116.       {
  117.         result = null;
  118.       }
  119.  
  120.       return true;
  121.     }
  122.  
  123.     public override string ToString()
  124.     {
  125.       return value ?? "";
  126.     }
  127.   }
  128.  
  129.   public class Program
  130.   {
  131.     public static void Main(string[] args)
  132.     {
  133.       var record = "A0120120214".AsDynamic();
  134.  
  135.       record(col1: 1, col2: 2, col3: 8);
  136.  
  137.       string col1 = record.col1;
  138.       Console.WriteLine(col1);
  139.  
  140.       int col2 = record.col2;
  141.       Console.WriteLine(col2);
  142.  
  143.       DateTime col3 = record.col3;
  144.       Console.WriteLine(col3);
  145.  
  146.       Console.WriteLine(record);
  147.  
  148.       // [Results]
  149.       // A
  150.       // 1
  151.       // 2012/02/14 0:00:00
  152.       // col1:A, col2:01, col3:20120214
  153.     }
  154.   }
  155. }

 

半分以上は@neueccさんのコードを流用させていただきました。(さんくす!)

ちょっと工夫した点は次の通り。

  • StringMemberクラスでDateTime型へのConvertを可能にした。(TryConvertメソッド)
  • 名前付き引数は、レコードの各項目を切り出す際の長さを指定するために使うようにした。

くらいでしょうか。

まだ複数行読み込んだ場合などに対応していない状態なので、APIを検討しつつもう少し洗練させてもよさそうですね。

 

なんにせよ、やってみたら案外dynamicを扱うのは簡単でした。(もちろん@neueccさんのおかげですけどね!)

まだまだdynamicな世界の可能性は広がっていそうですので、今後もちょろちょろと試して行ってみるつもりです。

皆さんもぜひやってみてくださいね。

 

[2012/2/16追記]

ソースはGistにも上げてあります。