仕様を見ても、ソースコードを見ても、コンテンツ中のURLから勝手にひろってトラックバックを送信してくれるはずなのだが、どうもうまくいかない。
うーん。もう一息。
IISログ見る限りだとおくってるようだし、受けているようなんだけどなぁ・・・。
2007年11月より、GyaoではSilverlightを利用した動画配信サービスとしてGAGA USENの最新映画の予告編をまとめた映像配信を行なっており、MacintochでのGyaO視聴も含めた本格採用に向けて検討を進めるとしていた。なお、「新着STATION」はMacでも表示できるが、リンク先の配信ページは従来通りのため、Macでの動画再生は行なえない。
おかげで、Macでも少しずつみられるようになってきた。
940900 (http://support.microsoft.com/kb/940900/)FIX: .NET Framework 2.0 に基づいて構築されるアプリケーションで String.IsNullOrEmpty 関数を呼び出すとき、 NullReferenceException 例外が発生します。
2007/12/10にリリースノートが出ていました。
3.5待ちという結論だったのが2.0でも修正されているのはうれしいですね。
過去のエントリ
検証すればよいのですが・・・。
既にKB 940900でHOTFIXは出ていたのですが、SP1に含まれているのかな。
リリースノートが準備中なんですよね。
.NET Framework 2.0のIsNullOrEmptyの不具合修正はSP1に含まれているのだろうか。 – NAL-6295の舌先三寸
そしてこの .NET Framework 3.0 SP1 に、今回の新機能を実行するためのライブラリを合わせたものが、.NET Framework 3.5 ということになります。
.NET Framework 3.5 = .NET Framework 3.0 SP1 + DLINQ, AJAX, …
= (( .NET Framework 2.0 × Update ) + WPF + WCF + WF + CS ) × Update + DLINQ, AJAX, …
これだけ見ていると頭が混乱しそうですが、実際には.NET Framework 3.5 のインストーラを使用してインストールすれば、必要なものがすべてインストールされる形になります。
ディベロッパー製品開発統括部 Blog : .NET Framework 3.5 と、.NET Framework 3.0および2.0 の関係
.NET Framework1.1と2.0の関係から考えると、.NET Framework2.0以降のバージョン間の関係は分かりづらいものがありますので、この記事を見て知っておく必要がありますね。
拡張メソッドを使ってみたかったので、ちょっと遊んでみます。
以前、LINQを利用して、読みやすいコードを書くサンプルとして以下のようなコードを提示していました。
class 在庫計 { public int 数量計 { get; set; } public int 金額計 { get; set; } } public class サンプル { public void サンプルメソッド(在庫[] 在庫リスト) { Func<在庫, bool> 集計対象 = 在庫情報 => { if (在庫情報.数量 <= 10) { return false; } if (在庫情報.数量 % 1000 != 0) { return false; } return true; }; var 在庫計情報 = 集計(在庫リスト,集計対象); System.Windows.Forms.MessageBox.Show(string.Format("数量計 = {0},金額計 = {1} ", 在庫計情報.数量計, 在庫計情報.金額計)); } private 在庫計 集計(在庫[] 在庫リスト,Func<在庫,bool> 集計対象) { 在庫計 在庫計情報 = new 在庫計(); 在庫計情報.数量計 = 在庫リスト .Where(集計対象) .Sum(x => x.数量); 在庫計情報.金額計 = 在庫リスト .Where(集計対象) .Sum(x => x.金額); return 在庫計情報; } }
集計メソッドで在庫リストにある数量と金額の合計を作成するわけですが、集計メソッドに在庫リストと抽出条件を引数で渡しているだけなので、特に在庫リストに結びついた処理であるといった情報はありません。
そこで拡張メソッドを利用したサンプルを書いてみます。
class 在庫計 { public int 数量計 { get; set; } public int 金額計 { get; set; } } class サンプル { public void サンプルメソッド(在庫[] 在庫リスト) { Func<在庫, Boolean> 抽出条件 = 在庫情報 => { if (在庫情報.数量 <= 10) { return false; } if (在庫情報.数量 % 1000 != 0) { return false; } return true; }; var 在庫計情報 = 在庫リスト.集計(抽出条件); System.Windows.Forms.MessageBox.Show(string.Format("数量計 = {0},金額計 = {1} ", 在庫計情報.数量計, 在庫計情報.金額計)); } } static class 在庫処理拡張サンプル { public static 在庫計 集計(this 在庫[] 在庫リスト, Func<在庫, Boolean> 抽出条件) { 在庫計 在庫計情報 = new 在庫計(); var result = from 在庫情報 in 在庫リスト where 抽出条件(在庫情報) select 在庫情報; 在庫計情報.数量計 = result.Sum(x => x.数量); 在庫計情報.金額計 = result.Sum(x => x.金額); return 在庫計情報; } }
この例の場合、在庫リスト.集計とコーディングできるため、「在庫リストの集計」と読むことができて、より文脈に沿ったコードを書くことができるようになりました。
まぁ、在庫リストなんて在庫の配列があるかといえば、だいたいにおいて在庫テーブルにアクセスするクラスがあって、そこに集計メソッドがあれば済む話なので拡張メソッドを利用する事は無いし、あまり多用するものでもないのですが、今回の例みたいに
「特定の配列に処理を追加したい。」
なんてときには便利かもしれません。
LINQに普通のJoinのほかにGroupJoinという機能がありますので、ちょっと使って遊んでみました。
通常のJoinの場合
var 商品リスト = new[] { new { 商品番号 = "A", 商品名 = "鼻毛カッター" }, new { 商品番号 = "B", 商品名 = "安全ハサミ" }, new { 商品番号 = "C", 商品名 = "ラジオペンチ"}}; var 在庫リスト = new[] { new { 商品番号 = "A", 数量 = 30 ,LotNo = 1} , new { 商品番号 = "A", 数量 = 40 ,LotNo = 2} , new { 商品番号 = "A", 数量 = 50 ,LotNo = 3} , new { 商品番号 = "A", 数量 = 60 ,LotNo = 4} , new { 商品番号 = "A", 数量 = 70 ,LotNo = 5} , new { 商品番号 = "A", 数量 = 90 ,LotNo = 6} , new { 商品番号 = "A", 数量 = 80 ,LotNo = 7} , new {商品番号 = "C",数量 = 69,LotNo = 8}}; var 商品別LOTNO別リスト = from 商品 in 商品リスト join 在庫 in 在庫リスト on 商品.商品番号 equals 在庫.商品番号 select new { 商品番号 = 商品.商品番号, 商品名 = 商品.商品名, LOTNO = 在庫.LOTNO, 数量 = 在庫.数量 };
というように二つの匿名型の配列を商品番号で結合したときの結果は
var 商品別LOTNO別リスト = new[] { new { 商品番号 = "A", 商品名 = "鼻毛カッター", 数量 = 30 ,LotNo = 1} , new { 商品番号 = "A", 商品名 = "鼻毛カッター", 数量 = 40 ,LotNo = 2} , new { 商品番号 = "A", 商品名 = "鼻毛カッター", 数量 = 50 ,LotNo = 3} , new { 商品番号 = "A", 商品名 = "鼻毛カッター", 数量 = 60 ,LotNo = 4} , new { 商品番号 = "A", 商品名 = "鼻毛カッター", 数量 = 70 ,LotNo = 5} , new { 商品番号 = "A", 商品名 = "鼻毛カッター", 数量 = 90 ,LotNo = 6} , new { 商品番号 = "A", 商品名 = "鼻毛カッター", 数量 = 80 ,LotNo = 7} , new {商品番号 = "C",, 商品名 = "ラジオペンチ", 数量 = 69,LotNo = 8}};
というように、SQLでINNER JOINをする時と同じような結果になります。
つまり、商品リストの商品番号に対して在庫リスト中に同じ商品番号があれば、それだけオブジェクトが作られます。
もちろん、対象の商品番号が無かったオブジェクトは作られません。
大して、
var 商品リスト = new[] { new { 商品番号 = "A", 商品名 = "鼻毛カッター" }, new { 商品番号 = "B", 商品名 = "安全ハサミ" }, new { 商品番号 = "C", 商品名 = "ラジオペンチ"}}; var 在庫リスト = new[] { new { 商品番号 = "A", 数量 = 30 ,LotNo = 1} , new { 商品番号 = "A", 数量 = 40 ,LotNo = 2} , new { 商品番号 = "A", 数量 = 50 ,LotNo = 3} , new { 商品番号 = "A", 数量 = 60 ,LotNo = 4} , new { 商品番号 = "A", 数量 = 70 ,LotNo = 5} , new { 商品番号 = "A", 数量 = 90 ,LotNo = 6} , new { 商品番号 = "A", 数量 = 80 ,LotNo = 7} , new {商品番号 = "C",数量 = 69,LotNo = 8}}; var 商品別在庫リスト = from 商品 in 商品リスト join 在庫 in 在庫リスト on 商品.商品番号 equals 在庫.商品番号 into 商品別在庫 select new { 商品番号 = 商品.商品番号, 商品名 = 商品.商品名, 数量 = 商品別在庫.Sum(x => x.数量) }; foreach (var 商品別在庫 in 商品別在庫リスト) { Console.WriteLine(string.Format("商品番号:{0} 商品名:{1} 在庫数量:{2}", 商品別在庫.商品番号, 商品別在庫.商品名, 商品別在庫.数量)); }
Join … Intoという構文で上記のようにGroupJoinをすると、
var 商品別在庫リスト = new[] { new { 商品番号 = "A", 商品名 = "鼻毛カッター" ,数量 = 420}, new { 商品番号 = "B", 商品名 = "安全ハサミ" ,数量 = 0}, new { 商品番号 = "C", 商品名 = "ラジオペンチ",数量 = 69}};
というように、商品リストの商品番号と同じ商品番号の在庫は集約されて結合されますので、商品番号単位に在庫リストが作成されることになり、商品番号別の数量の合計を出力する事が可能です。
また、在庫リストに対象の商品番号が無いオブジェクトも作られます。
最初に断っておきたいこと
C#3.0の話です。 LINQやラムダ式自体の説明はしていません。 簡単なサンプルにするため仕様がシンプルで効果を感じられないかもしれませんが、 もしもっと複雑な仕様だったら等、想像してみてください。
まず最初に、下記のサンプルを見てください。
簡単な仕様として、
受け取った在庫リストの集計対象のものだけ集計したい。 集計対象とは、数量が10より大きくて、数量を1000で割った時の余りが0のものの事である。
を実現します。
class サンプル1 { private class 在庫計 { public int 数量計 { get; set; } public int 金額計 { get; set; } } public void サンプルメソッド(在庫[] 在庫リスト) { 在庫計 在庫計情報 = new 在庫計(); foreach (在庫 在庫情報 in 在庫リスト) { if (在庫情報.数量 > 10) { if ((在庫情報.数量 % 1000 == 0)) { 在庫計情報.数量計 += 在庫情報.数量; 在庫計情報.金額計 += 在庫情報.金額; } } } } }
この例の場合、たしかに仕様を実現していますが、if文が実現している仕様についてコード上から読み取ることができません。
そこで、ラムダ式を利用し、集計対象の時にtrueを返す匿名メソッドを作成して実装してみます。
class サンプル2 { private class 在庫計 { public int 数量計 { get; set; } public int 金額計 { get; set; } } public void サンプルメソッド(在庫[] 在庫リスト) { Func<在庫, Boolean> 集計対象 = 在庫情報 => { if (在庫情報.数量 <= 10) { return false; } if (在庫情報.数量 % 1000 != 0) { return false; } return true; }; 在庫計 在庫計情報 = new 在庫計(); foreach (在庫 在庫情報 in 在庫リスト) { if (集計対象(在庫情報)) { 在庫計情報.数量計 += 在庫情報.数量; 在庫計情報.金額計 += 在庫情報.金額; } } }
その結果、集計対象の在庫のみ集計するという部分と、集計対象である条件の詳細部分が分離されました。
ここでさらにLINQを利用して、ループの部分が実際に何をしているのかをコードに残すようにします。
public class サンプル3 { public void サンプルメソッド(在庫[] 在庫リスト) { Func<在庫, bool> 集計対象 = 在庫情報 => { if (在庫情報.数量 <= 10) { return false; } if (在庫情報.数量 % 1000 != 0) { return false; } return true; }; var 在庫計情報 = new { 数量計 = 在庫リスト .Where(集計対象) .Sum(x => x.数量), 金額計 = 在庫リスト .Where(集計対象) .Sum(x => x.金額) }; } }
もしくは、
public class サンプル4 { public void サンプルメソッド(在庫[] 在庫リスト) { Func<在庫, bool> 抽出条件 = 在庫情報 => { if (在庫情報.数量 <= 10) { return false; } if (在庫情報.数量 % 1000 != 0) { return false; } return true; }; var 在庫計情報 = new { 数量計 = (from 在庫情報 in 在庫リスト where 抽出条件(在庫情報) select 在庫情報.数量).Sum() , 金額計 = (from 在庫情報 in 在庫リスト where 抽出条件(在庫情報) select 在庫情報.金額).Sum() }; } }
その結果、ループがなくなりましたが、在庫リストから集計対象のもののみを抽出(Where)し、集計(Sum)している事がコードに埋め込まれました。
また、在庫計情報をループで加算しないため、サンプル2までは在庫計というinner classを作成していましたが、その必要がなくなり、その場限りの匿名型で済むようになりました。
ところでサンプルコードだけを見ているとわかりませんが、集計した結果がint型の範囲を超えた時、サンプル2まで(ループで集計している)とサンプル3以降(LINQを利用している。)で実行時の挙動が違います。
サンプル2までは、例外が発生せず、マイナス値になってしまいます。
サンプル3以降は、ちゃんとOverflowExceptionが発生します。
もしサンプル2までのコードで例外が発生するようにする場合は
単純に
//抜粋 foreach (在庫 在庫情報 in 在庫リスト) { if (集計対象(在庫情報)) { if (在庫計情報.金額計 + 在庫情報.金額 > int.MaxValue) { throw new OverflowException(); } 在庫計情報.数量計 += 在庫情報.数量; 在庫計情報.金額計 += 在庫情報.金額; } }
とすると、intの範囲を超えた場合
在庫計情報.金額計 + 在庫情報.金額
がマイナス値になるため
在庫計情報.金額計 + 在庫情報.金額 > int.MaxValue
の条件がtrueになることが無いため、いつまでも例外が発生しません。
そのためより値のとれる範囲の大きいlongに型変換したうえで、
//抜粋 foreach (在庫 在庫情報 in 在庫リスト) { if (集計対象(在庫情報)) { if ((long)在庫計情報.金額計 + (long)在庫情報.金額 > int.MaxValue) { throw new OverflowException(); } 在庫計情報.数量計 += 在庫情報.数量; 在庫計情報.金額計 += 在庫情報.金額; } }
とするか、金額にマイナス値が無い前提であれば、
//抜粋 foreach (在庫 在庫情報 in 在庫リスト) { if (集計対象(在庫情報)) { if (在庫計情報.金額計 + 在庫情報.金額 < 0) { throw new OverflowException(); } 在庫計情報.数量計 += 在庫情報.数量; 在庫計情報.金額計 += 在庫情報.金額; } }
とする必要があります。
つまり、うっかり間違った実装をしてしまうと、オーバフロー時に例外を発行させているつもりで、実は発行していないという状況になってしまいますので、そういう点でも、このくらいの集計ならLINQを利用した方が安全です。