Hatena::ブログ(Diary)

当面C#と.NETな記録 このページをアンテナに追加 RSSフィード

2007/11/29 (木)

[] LINQ でフィボナッチ (危険)  LINQ でフィボナッチ (危険)を含むブックマーク  LINQ でフィボナッチ (危険)のブックマークコメント

動いちゃったのでさらします。真似しちゃダメっぽいです。Max を大きくすると大変なことになります。

どう動いているのだろ(^^; 頭がついていきません…w

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

class Program
{
    private const int Max = 20;

    static void Main()
    {
        int[] fibo = new int[ Max ];
        fibo[ 0 ] = 1;
        fibo[ 1 ] = 1;
        for ( int i = 1; i < Max - 1; i++ )
            fibo[ i + 1 ] = fibo[ i - 1 ] + fibo[ i ];

        foreach ( int i in fibo )
            Console.Write( "{0,8}", i );
        Console.WriteLine();
        Console.WriteLine();

        // LINQ
        IEnumerable<int> fibLinq = null;
        fibLinq = new int[] { 1, 1 }.
          Concat(
            Enumerable.Range( 1, Max - 2 ).
              Select( n => fibLinq.ElementAt( n - 1 ) + fibLinq.ElementAt( n ) ) );

        foreach ( int i in fibLinq )
            Console.Write( "{0,8}", i );

        Console.WriteLine( fibo.SequenceEqual( fibLinq ) );
        Console.ReadKey();
    }
}

まさかコンパイル通ったり、ましてや動いてしまうとは思いませんでした。

[] りんくあそび  りんくあそびを含むブックマーク  りんくあそびのブックマークコメント

LINQ の練習に WMI ネタとフィボナッチネタのバリエーションをいろいろ書いて試してますが、インテリセンスがついてくるのがスゴイですね。ときどきあるんですが、文法は正しいのに表示しなくなったら、一度ビルドすればまた表示してくれるようになります。

悩んでるのはクエリー式のデバッグってどうするんだろってとこ。ひとかたまりで成功か失敗か、しかできないのかな…。小技だけど、ラムダ式の goes to (「=>」のこと)の後に改行入れるとブレーク貼れますね。あと「select n」ってあるとき、「select 改行 n」とすれば n にブレーク貼れます。改行しないで n の上で右クリックでも OK。

コード公開で yield の中まで行けるのかな?でも、入って行けても頭がついていかないのが問題か…。2.0で LINQ もどきを試したときは、yield 連鎖がいくつかあると、ステップ実行すると頭が混乱しました。

ところで、数日間、あいぴいあんりーちゃぶるになります。ネット依存脱出キャンプに行ってきます(うそですw)。コメントやトラバでとても盛り上がっているところですが、スミマセン。RSS で読んでると、もしかしてコメントやトラバに気づいてないかもしれませんが、おもしろいネタ話題がいっぱいです。返事は遅くなりますが、コメントはいつでも歓迎です。LINQ の変なコードだったりすると特に喜びますw

nsharpnsharp 2007/11/29 06:50 こんなおそろしいコードも動いてしまいます。w

static IEnumerable<int> Fib() {
  yield return 1;
  yield return 1;

  using (var e1 = Fib().GetEnumerator())
  using (var e2 = Fib().Where((v, i) => i > 0).GetEnumerator()) {
    while (e1.MoveNext() && e2.MoveNext()) {
      yield return e1.Current + e2.Current;
    }
  }
}

// Fib().Take(20)

siokoshousiokoshou 2007/11/29 10:52 これまた、動きがわかりませんw
e2 は Where で 0 を飛ばしてるんですね!すんごいトリッキーw
今日はこいつらが頭から離れなそう…

siokoshousiokoshou 2007/11/29 12:46 Where((v, i) => i > 0)

Skip(1)
で置き換えできますね。

nsharpnsharp 2007/11/29 14:27 やってることは実はHaskellのこれのベタ移植だったりして。w
ttp://www.sampou.org/haskell/tutorial-j/functions.html#sect3.4

> Skip(1)

あー、気づきませんでした。どうもです。
本当にいろんな書き方ができるので困る。w

siokoshousiokoshou 2007/11/29 18:49 本当にいろいろ書けますよね。あと、WMI ネタで触れてた、クエリー式と拡張メソッドで書く場合の表現力の違いもいろいろありますね〜。
↑これも最初はHaskellのマネしようとしてて、うまくできなくて、ためしにこうやってみたら動いてしまったってネタでしたw

nsharpnsharp 2007/11/29 23:37 > 数日間、あいぴいあんりーちゃぶるになります。

そんなときに限って、Pの付くLINQが出ちゃったりして・・・。w

siokoshousiokoshou 2007/11/30 05:13
http://blogs.zdnet.com/microsoft/?p=991
出てもどうせ性能を測れるマシンがないので(´;ω;`)ぶわっ

NyaRuRuNyaRuRu 2007/11/30 07:26 ParallelFXもF#のasyncもThreadPoolべったり依存なのでXbox 360 CLRとは相性悪いんですよね……
個人的にはMPIみたいなのも欲しい.

トラックバック - http://d.hatena.ne.jp/siokoshou/20071129

2007/11/28 (水)

[] C#VB  C# と VBを含むブックマーク  C# と VBのブックマークコメント

http://www.google.com/trends?q=c%23%2C+VB&ctab=0&geo=all&date=all&sort=0

日本だけは VB 大国?

Redmond は C# にかなり偏ってるようですが。

トラックバック - http://d.hatena.ne.jp/siokoshou/20071128

2007/11/27 (火)

[] リンク切れ  リンク切れを含むブックマーク  リンク切れのブックマークコメント

VC#2008Express英語版入れて遊んでますが、ドキュメントのリンク切れがひどいですね…。RC出しとけばよかったのに…。日本語版だと直ってたりしないかと超期待。

[] LINQ で WMI その3  LINQ で WMI その3を含むブックマーク  LINQ で WMI その3のブックマークコメント

id:siokoshou:20071124 のクエリーを少しだけスッキリさせてみた。

Func<object, Dictionary<int, string>, string> map =
  ( o, d ) => d == null ? o.ToString() : d[ ToInt( o ) ];

var query =
  from ManagementObject mo in ( new ManagementClass( "Win32_CacheMemory" ) ).GetInstances()
  from PropertyData prop in mo.Properties
  join m in WmiWin32CacheMemoryMessages on prop.Name equals m.Key into mm
  from mes in mm.DefaultIfEmpty()
  select prop.Value == null ?
    new { prop.Name, Value = "null" } :
    !prop.IsArray ?
      new { prop.Name, Value = map( prop.Value, mes.Value ) } :
      new { prop.Name, Value =
        string.Join( ", ",
          ( from object o in prop.Value as Array select map( o, mes.Value ) ).ToArray() )
      };

クエリー式の文法がよくわかりません!

あと、どう書いたら読みやすいのか、手探りで模索中。今のところ、慣れてないのでどう書いてもキモイw

匿名型のプロパティ名、「new { prop.Name, Value = "null" }」と書くと一つ目のプロパティ名は Name になるんでした。もう忘れてた(^^;

nsharpnsharp 2007/11/28 12:20 解読を試みましたが、こんなところが限界です。(;´Д`)
(横長失礼・・・)

var propValues = new Func<PropertyData, IEnumerable<object>>(p => p.IsArray && p.Value != null
  ? ((Array) p.Value).Cast<object>() : Enumerable.Repeat(p.Value, 1)
);
var toString = new Func<object, Dictionary<int, string>, string>((v, d) => d != null && v != null
  ? d[ToInt(v)] : (v == null ? ”null” : v.ToString())
);

var query =
  from ManagementObject mobj in new ManagementClass(”Win32_CacheMemory”).GetInstances()
  from PropertyData prop in mobj.Properties
  let dict = WmiWin32CacheMemoryMessages.ContainsKey(prop.Name) ? WmiWin32CacheMemoryMessages[prop.Name] : null
  let vals = from v in propValues(prop) select toString(v, dict)
  select new { prop.Name, Value = String.Join(”,”, vals.ToArray()) };

siokoshousiokoshou 2007/11/28 12:37 ちょっw だんだんパズル大会にw
> Enumerable.Repeat
で無理やりシーケンスにしてるところに感動
var の 右辺で new Func<> って書き方があったんですね!なるほど!
あ、Dictionary に拡張メソッドで DefaultEmpty なゲッターを書けばさらにスッキリ?

nsharpnsharp 2007/11/28 12:40 あ、toStringの型の順番が逆だった・・・。orz

本当はカリー化させた方がきれいなんですけど、

  Func<Dictionary<int, string>, Func<object, string>>

クエリー構文では部分適用が活きないんですよね・・・。(´・ω・`)

  let vals = from v in propValues(prop) select toString(dict)(v)

拡張メソッドならラムダを消せるんですけど・・・。

  let vals = propValues(prop).Select(toString(dict))

siokoshousiokoshou 2007/11/28 22:54 ↑コンパイルが通せません(>_<) どうしたらいいんだろ…
toString の引数の順番を入れ替えて、

var toString = new Func<Dictionary<int, string>, object, string>( ( d, v ) =>
d != null && v != null ?
d[ ToInt( v ) ] :
( v == null ? ”null” : v.ToString() ) );

で、

var fun = null as Func<Dictionary<int, string>, Func<object, string>>;

こうしておいて、

let func = toString( dict )

とかしてみたけど通らず…

siokoshousiokoshou 2007/11/28 23:25 あ、こうか!
var toString = new Func<Dictionary<int, string>, Func<object, string>>( d =>
( v =>
d != null && v != null ?
d[ ToInt( v ) ] : ( v == null ? ”null” : v.ToString() ) ) );

できた!おもしろいw

トラックバック - http://d.hatena.ne.jp/siokoshou/20071127

2007/11/26 (月)

[] LINQ パズル  LINQ パズルを含むブックマーク  LINQ パズルのブックマークコメント

http://www.infoq.com/news/2007/11/Functional-CSharp

int[] b = Enumerable.Range( 1, 20 ).ToArray();

Correct?

using System;
using System.Linq;

class P
{
    static void Main()
    {
        int[] a = new int[ 20 ];
        for ( int x = 0; x < a.Length; x++ )
            a[ x ] = x + 1;

        int[] b = Enumerable.Range( 1, 20 ).ToArray();

        Console.WriteLine( a.SequenceEqual( b ) );
        Console.ReadKey();
    }
}

おまけ

int[] c = new int[ 20 ];
for ( int x = 0; x < c.Length; x++ )
  c[ x ] = x * 2;

int[] d = Enumerable.Range( 0, 20 ).Select( n => n * 2 ).ToArray();
Console.WriteLine( c.SequenceEqual( d ) );

NyaRuRuNyaRuRu 2007/11/26 09:20 そろそろブラウザ内で C# のサンプルコードを読み書き実行する機能が欲しいですねぇ.
Silverlight で作れそう?

siokoshousiokoshou 2007/11/26 10:33 おおお、欲しいですね!夢が広がりんぐ

トラックバック - http://d.hatena.ne.jp/siokoshou/20071126

2007/11/25 (日)

[] LINQ to Object の資料  LINQ to Object の資料を含むブックマーク  LINQ to Object の資料のブックマークコメント

LINQ だけで本が何冊も出てくると予想してますが、早く日本語の良い本が一冊欲しいなぁ。ITマスコミが LINQ の記事をあまり書かないのは、LINQ が何なんなのか理解されていないからっぽいですね。某所のクイズを見てそれ正解じゃないからとか思ったり。LINQ の一番の特徴はデータソースを問わないってとこかと。

MS の日本語による情報 (内容は一部古いかも)

そのほか ここ からいろいろと。

あと、LINQ to Object は説明を読むよりソースコードを読んだほうが理解できる場面が多々あるので、コードが降ってくるまでは Mono のコード をどうぞ。

余談だけど関数型言語の本もその言語の標準ライブラリをコードを示して説明していきますよね。LINQ もやっぱりコードを読むと理解できる場面があります。クエリ式の変換則は説明読むしかないけど。

英語はつらいけど LINQ の練習にはチュートリアルが必要だなぁと感じるので、ちょっと探してみようかな。でも英語苦手…。

[] LINQ to Object のイディオム その1 : Cast<T>() と OfType<T>()  LINQ to Object のイディオム その1 : Cast<T>() と OfType<T>()を含むブックマーク  LINQ to Object のイディオム その1 : Cast<T>() と OfType<T>()のブックマークコメント

昨日の LINQ to Object コードが読めなくなる前に(^^; メモを少し書き散らしておきます。

  • IEnumerable を LINQ to Object で扱うには Cast<T>() か OfType<T>() で IEnumerable<T> に変換する。古くからある非ジェネリクスなコレクションを LINQ で扱うには変換必須。
  • Cast<T>() と OfType<T>() はどちらもシーケンスの各要素をキャストして列挙する
  • Cast<T>() はそのままキャストするだけ。キャストできないと例外が飛ぶ。(パイプと例外は相性が悪いけど、それはまた別の話)
  • OfType<T>() は is T だけ列挙する。is T でなければ飛ばす。IEnumerable シーケンスから T 型だけ抜き出すフィルタ。

実はこの違いはコード見れば一目で理解できるんですけどね(^^;

型混在のコレクションなんてあまり使わないので、Cast<T>() を主に使うと思います。クエリ式では Cast が簡単に書けるようになっていて、昨日のコードの

from PropertyData p in mo.Properties

mo.Properties.Cast<PropertyData>()

に変換されます。

ヘジたんによる説明は このあたり

2007/11/24 (土)

[] LINQ で WMI その2  LINQ で WMI その2を含むブックマーク  LINQ で WMI その2のブックマークコメント

昨日の WMI の id:siokoshou:20071123#p2 って外部結合ってやつじゃね?と思って、全部そのまま LINQ にしてみました。苦労した。でもタノシイ。単に select の部分がこってるだけなのが不満。もっと遊んでしまいそうな気が…。

WmiWin32CacheMemoryMessages テーブルと ToInt メソッドは昨日と同じです。

using System;
using System.Collections.Generic;
using System.Management;
using System.Linq;

namespace Wmi
{
  class Program
  {
    static void Main()
    {
      var query =
        from ManagementObject mo in
          ( new ManagementClass( "Win32_CacheMemory" ) ).GetInstances()
        from PropertyData p in mo.Properties
        join m in WmiWin32CacheMemoryMessages on p.Name equals m.Key into mm
        from m in mm.DefaultIfEmpty()
        select p.Value == null ?
          new { Name = p.Name, Value = "null" } :
          m.Value == null ?
            !p.IsArray ?
              new { Name = p.Name, Value = p.Value.ToString() } :
              new { Name = p.Name, Value = string.Join( ", ",
                ( from object o in p.Value as Array
                  select ToInt( o ).ToString() ).ToArray() )
              } :
            !p.IsArray ?
              new { Name = p.Name, Value = m.Value[ ToInt( p.Value ) ] } :
              new { Name = p.Name, Value = string.Join( ", ",
                ( from object o in p.Value as Array
                  select m.Value[ ToInt( o ) ] ).ToArray() )
              };

      foreach ( var item in query )
      {
        Console.WriteLine( item.Name + " : " + item.Value );
      }
      Console.ReadKey();
    }

    private static int ToInt( object o )
    {
      if ( o is UInt16 )
      {
        UInt16 u = ( UInt16 ) o;
        return ( int ) u;
      }
      else if ( o is UInt32 )
      {
        UInt32 u = ( UInt32 ) o;
        return ( int ) u;
      }
      throw new ArgumentException( "Unknown Type", "o" );
    }

        private static Dictionary<string, Dictionary<int, string>> WmiWin32CacheMemoryMessages =
            new Dictionary<string, Dictionary<int, string>> {
            { "Access", new Dictionary<int, string> {
               { 0, "Unknown" }, { 1, "Readable" }, { 2, "Writable" }, { 3, "Read/Write Supported" },
               { 4, "Windows Server 2003 and Windows XP:  Write Once" } } },
            { "Associativity", new Dictionary<int, string> {
               { 1, "Other" }, { 2, "Unknown" }, { 3, "Direct Mapped" }, { 4, "2-way Set-Associative" },
               { 5, "4-way Set-Associative" }, { 6, "Fully Associative" },
               { 7, "Windows Server 2003 and Windows XP:  8-way Set-Associative" },
               { 8, "Windows Server 2003 and Windows XP:  16-way Set-Associative" } } },
            { "Availability", new Dictionary<int, string> {
                { 1, "Other" }, { 2, "Unknown" }, { 3, "Running/Full Power" }, { 4, "Warning" },
                { 5, "In Test" }, { 6, "Not Applicable" }, { 7, "Power Off" }, { 8, "Off Line" },
                { 9, "Off Duty" }, { 10, "Degraded" }, { 11, "Not Installed" }, { 12, "Install Error" },
                { 13, "Power Save - Unknown  The device is known to be in a power save mode, but its exact status is unknown." },
                { 14, "Power Save - Low Power Mode  The device is in a power save state but still functioning, and may exhibit degraded performance." },
                { 15, "Power Save - Standby  The device is not functioning but could be brought to full power quickly." },
                { 16, "Power Cycle" },
                { 17, "Power Save - Warning  The device is in a warning state, though also in a power save mode." } } },
            { "CacheType", new Dictionary<int, string> {
                { 1, "Other" }, { 2, "Unknown" }, { 3, "Instruction" }, { 4, "Data" }, { 5, "Unified" } } },
            { "ConfigManagerErrorCode", new Dictionary<int, string> {
                { 0, "Device is working properly." },
                { 1, "Device is not configured correctly." },
                { 2, "Windows cannot load the driver for this device." },
                { 3, "Driver for this device might be corrupted, or the system may be low on memory or other resources." },
                { 4, "Device is not working properly. One of its drivers or the registry might be corrupted." },
                { 5, "Driver for the device requires a resource that Windows cannot manage." },
                { 6, "Boot configuration for the device conflicts with other devices." },
                { 7, "Cannot filter." },
                { 8, "Driver loader for the device is missing." },
                { 9, "Device is not working properly; the controlling firmware is incorrectly reporting the resources for the device." },
                { 10, "Device cannot start." },
                { 11, "Device failed." },
                { 12, "Device cannot find enough free resources to use." },
                { 13, "Windows cannot verify the device's resources." },
                { 14, "Device cannot work properly until the computer is restarted." },
                { 15, "Device is not working properly due to a possible re-enumeration problem." },
                { 16, "Windows cannot identify all of the resources that the device uses." },
                { 17, "Device is requesting an unknown resource type." },
                { 18, "Device drivers need to be reinstalled." },
                { 19, "Failure using the VxD loader." },
                { 20, "Registry might be corrupted." },
                { 21, "System failure. If changing the device driver is ineffective, see the hardware documentation. Windows is removing the device." },
                { 22, "Device is disabled." },
                { 23, "System failure. If changing the device driver is ineffective, see the hardware documentation." },
                { 24, "Device is not present, not working properly, or does not have all of its drivers installed." },
                { 25, "Windows is still setting up the device." },
                { 26, "Windows is still setting up the device." },
                { 27, "Device does not have valid log configuration." },
                { 28, "Device drivers are not installed." },
                { 29, "Device is disabled; the device firmware did not provide the required resources." },
                { 30, "Device is using an IRQ resource that another device is using." },
                { 31, "Device is not working properly; Windows cannot load the required device drivers." } } },
            { "CurrentSRAM", new Dictionary<int, string> { { 0, "Other" }, { 1, "Unknown" }, { 2, "Non-Burst" },
                { 3, "Burst" }, { 4, "Pipeline Burst" }, { 5, "Synchronous" }, { 6, "Asynchronous" } } },
            { "ErrorAccess", new Dictionary<int, string> { { 1, "Other" }, { 2, "Unknown" }, { 3, "Read" },
                { 4, "Write" }, { 5, "Partial Write" } } },
            { "ErrorCorrectType", new Dictionary<int, string> { { 0, "Reserved" }, { 1, "Other" },
                { 2, "Unknown" }, { 3, "None" }, { 4, "Parity" }, { 5, "Single-bit ECC" }, { 6, "Multi-bit ECC" } } },
            { "ErrorDataOrder", new Dictionary<int, string> { { 0, "Unknown" }, { 1, "Least Significant Byte First" },
                { 2, "Most Significant Byte First" } } },
            { "ErrorInfo", new Dictionary<int,string> { { 1, "Other" }, { 2, "Unknown" }, { 3, "OK" }, { 4, "Bad Read" },
                { 5, "Parity Error" }, { 6, "Single-Bit Error" }, { 7, "Double-Bit Error" }, { 8, "Multi-Bit Error" },
                { 9, "Nibble Error" }, { 10, "Checksum Error" }, { 11, "CRC Error" }, { 12, "Undefined" },
                { 13, "Undefined" }, { 14, "Undefined" } } },
            { "Level", new Dictionary<int,string> { { 1, "Other" }, { 2, "Unknown" }, { 3, "Primary" },
                { 4, "Secondary" }, { 5, "Tertiary" }, { 6, "Windows Server 2003 and Windows XP:  Not Applicable" } } },
            { "Location", new Dictionary<int,string> {
                { 0, "Internal" }, { 1, "External" }, { 2, "Reserved" }, { 3, "Unknown" } } },
            { "PowerManagementCapabilities", new Dictionary<int,string> {
                { 0, "Unknown" },
                { 1, "Not Supported" },
                { 2, "Disabled" },
                { 3, "Enabled  The power management features are currently enabled but the exact feature set is unknown or the information is unavailable." },
                { 4, "Power Saving Modes Entered Automatically  The device can change its power state based on usage or other criteria." },
                { 5, "Power State Settable  The SetPowerState method is supported. This method is found on the parent CIM_LogicalDevice class and can be implemented. For more information, see Extending Your Management Capabilities." },
                { 6, "Power Cycling Supported  The SetPowerState method can be invoked with the PowerState parameter set to 5 (Power Cycle)." },
                { 7, "Timed Power On Supported  The SetPowerState method can be invoked with the PowerState parameter set to 5 (Power Cycle) and Time set to a specific date and time, or interval, for power-on." },
            } },
            { "ReadPolicy", new Dictionary<int,string> { { 1, "Other" }, { 2, "Unknown" }, { 3, "Read" },
                { 4, "Read-Ahead" }, { 5, "Read and Read-Ahead" },
                { 6, "Windows Server 2003 and Windows XP:  Determination Per I/O" } } },
            { "ReplacementPolicy", new Dictionary<int,string> { { 1, " Other" }, { 2, " Unknown" },
                { 3, " Least Recently Used (LRU)" }, { 4, " First In First Out (FIFO)" },
                { 5, " Last In First Out (LIFO)" }, { 6, " Least Frequently Used (LFU)" },
                { 7, " Most Frequently Used (MFU)" },
                { 8, "Windows Server 2003 and Windows XP:  Data Dependent Multiple Algorithms" } } },
            { "StatusInfo", new Dictionary<int,string> { { 1, "Other" }, { 2, "Unknown" }, { 3, "Enabled" },
                { 4, "Disabled" }, { 5, "Not Applicable" } } },
            { "SupportedSRAM", new Dictionary<int,string> { { 0, "Other" }, { 1, "Unknown" }, { 2, "Non-Burst" },
                { 3, "Burst" }, { 4, "Pipeline Burst" }, { 5, "Synchronous" }, { 6, "Asynchronous" } } },
            { "WritePolicy", new Dictionary<int,string> { { 1, "Other" }, { 2, "Unknown" }, { 3, "Write Back" },
                { 4, "Write Through" }, { 5, "Varies with Address" },
                { 6, "Windows Server 2003 and Windows XP:  Determination Per I/O " } } }
            };
    }
}

本当はこんなことをするために WMI いじりはじめたんじゃないんだけど…、イイノカ、オレw

siokoshousiokoshou 2007/11/24 10:58 テーブルは別として、コードはちょっといじれば WMI 汎用になるんだけど、そもそも誰も読めないよなぁw

トラックバック - http://d.hatena.ne.jp/siokoshou/20071124

2007/11/23 (金)

[] object initializer は atomic  object initializer は atomicを含むブックマーク  object initializer は atomicのブックマークコメント

http://community.bartdesmet.net/blogs/bart/archive/2007/11/22/c-3-0-object-initializers-revisited.aspx

オブジェクト初期化子って↓こういうやつね。

Customer c = new Customer() { Name = "Bart", City = "Redmond", Age = 24 };

中途半端な状態は作らないよー、だって。よく考えてあるなぁ。仕様書にも atomic の一言が入ってればわかりやすいのに。

[] はじめての WMI  はじめての WMIを含むブックマーク  はじめての WMIのブックマークコメント

WMI 初めて使いました。MSDN の宇宙語っぷりにクラクラしたけど、宇宙仮面さんが解読済みだったので助かりました。ありがとうございます。

Win32_CacheMemory の手抜きサンプル書いてみました。

値の意味の文字列はどっかから取れないのかなぁ。コピペして Ctrl+H で VS の正規表現の練習大会になってしまいました。疲れた。

Dictionaryの初期化 ( via id:Nobuhisa:20071117:1195238968 ) も参考になりました。ありがとうございます。

「var dic = new Dictionary<string, int>(){ { "one", 1 }, { "two", 2 }, { "three", 3 } };」

続きを読む

[] LINQ で WMI  LINQ で WMIを含むブックマーク  LINQ で WMIのブックマークコメント

せっかくなので LINQ で。

using System;
using System.Management;
using System.Linq;

class P
{
  static void Main()
  {
    var query = from mo in ( new ManagementClass( "Win32_CacheMemory" ) ).
                    GetInstances().OfType<ManagementObject>()
                from p in mo.Properties.OfType<PropertyData>()
                where p.Name == "InstalledSize"
                select p.Value;

    Console.WriteLine( query.ElementAt( 0 ) );
    Console.ReadKey();
  }
}

LINQ はまだよちよち歩きです。Luke 教祖様との彼我の距離を感じますた。

LINQ 最大の欠点はその中毒性ですねw

トラックバック - http://d.hatena.ne.jp/siokoshou/20071123

2007/11/22 (木)

[] 拡張メソッドと null  拡張メソッドと nullを含むブックマーク  拡張メソッドと nullのブックマークコメント

昨日は拡張メソッドの闇の面中心に書いたので、今度は光の面でも。

拡張メソッドの紹介記事によく出てくる string.IsNullOrEmpty() ですが、おもしろいことに気付きました。

using System;

class Program
{
  static void Main( string[] args )
  {
    string a = "test";
    Console.WriteLine( a.IsNullOrEmpty() );

    string b = string.Empty;
    Console.WriteLine( b.IsNullOrEmpty() );

    string c = null;
    Console.WriteLine( c.IsNullOrEmpty() );

    // Console.WriteLine( c.ToString() ); // NullReferenceException
    // Console.WriteLine( null.IsNullOrEmpty() ); // Operator '.' cannot be applied to operand of type '<null>'

    Console.ReadKey();
  }
}

static class Ext
{
  public static bool IsNullOrEmpty( this string str )
  {
    return string.IsNullOrEmpty( str );
  }
}

string c = null ってしといて、c.IsNullOrEmpty() が呼べてしまいます! null で呼べるんです。普通のインスタンスメソッドだと NullReferenceException が出てしまうけど、拡張メソッドだと動いてしまいます。これも引数と this になるものの違いですね。なお、露骨に null で null.IsNullOrEmpty() と呼ぼうとしたら、コンパイルエラーになりました。

ハックに使えそうな機能ですねw

トラックバック - http://d.hatena.ne.jp/siokoshou/20071122

2007/11/21 (水)

[] 拡張メソッド != 静的メソッド  拡張メソッド != 静的メソッドを含むブックマーク  拡張メソッド != 静的メソッドのブックマークコメント

C#3.0 の拡張メソッドの怖いお話。拡張メソッドと静的メソッドは構文の字面だけの違いで、ほかは同じだよと言われることが多いけど、実は違います。仕様書に書いてはあるけど、はっきり注意を喚起していないので。拡張メソッドの仕様はこちら

念のため引用。「拡張メソッドは、インスタンス メソッドに比べて、見つけにくく、機能も限られています。このため、拡張メソッドの使用はできるだけ控え、インスタンス メソッドが適していない場合や使用できない場合にのみ使用することをお勧めします。」拡張メソッドは飛び道具だから振り回さないほうがイイですね。

関連ネタ : id:siokoshou:20070901#p2, id:siokoshou:20070903#p1

via http://blogs.msdn.com/sreekarc/archive/2007/10/11/consequences-of-conversion-rules-for-instance-parameters.aspx

Sreekar さんの説明よりずっと詳しく書きました。コンパイラチームに負けないぜぃw

using System;

class Program
{
  static void Main()
  {
    0.Foo();       // 1
    0L.Foo();
    Console.WriteLine();

    Ext.Foo( 0 );  // 2
    Ext.Foo( 0L );
    Console.ReadKey();
  }
}

static class Ext
{
  public static void Foo( this long x ) { Console.WriteLine( "long" ); }
  //public static void Foo( this int x ) { Console.WriteLine( "int" ); }
  public static void Foo( this object x ) { Console.WriteLine( "Object" ); }
  public static void Foo( this short x ) { Console.WriteLine( "short" ); }
  //public static void Foo( this sbyte x ) { Console.WriteLine( "sbyte" ); }
}

このコードで、1 と 2 はどれが呼ばれると思いますか?クイズにしても誰も正解しなそうなので自粛(^^;

1 は Object、2 は short が呼ばれます。インスタンスメソッド構文で呼んだ時と、静的メソッドとして呼んだときで違うメソッドが呼ばれています!イヤらしいですねぇ、何考えて設計したんでしょう。不用意な結びつきを避けたのかもしれません。(追記:この部分はこれまで意識していなかったインスタンスメソッドと静的メソッドの違いが拡張メソッドで意識できるようになったため、あらためて気付いたってだけのことかもしれません。id:siokoshou:20071121#p2 参照)

これは変換規則の違いによるものだそうで、拡張メソッドの1つめのパラメータの変換規則が従来と違うことが原因でこうなるそうです。上で挙げた仕様書の「1 つ目の引数から 1 つ目のパラメータへの暗黙的な、ID 変換、参照の変換、またはボックス化変換が存在しないメソッドをすべて除外します。」の部分でさらっと触れています。

ID 変換というのは、従来、恒等変換と訳されていたもの。変換しない変換規則です。参照の変換とボックス化変換はわかりますよね(詳細は別として(^^;)。

で、何が言いたいのかというと、「暗黙の数値変換」をはじめいくつかの暗黙の変換がなくなっていますよ、と。

Sreekar さんの blog では、これは暗黙の数値変換がないためと説明してますが、仕様をよく読むと、暗黙の定数式変換がないせいの誤りではないかと思われます(^^; ちょっと余談ですが、2 が long じゃなくて short なのは暗黙の数値変換規則ではなく、暗黙の定数式変換ルールが使われたためです。sbyte を取る Foo() のコメントを外すとこっちが呼ばれます。

以下、いくつか消えた変換規則のサンプルを。これを C# 仕様書に追記してもらいたいな。

using System;

class Program
{
  static void Main()
  {
    0.Foo();        // Object
    Ext.Foo( 0 );   // short 暗黙の定数式変換
    Console.WriteLine();

    B b = new B { Val = 1 };
    b.Foo();         // Object
    Ext.Foo( b );    // A
    Console.WriteLine();

    bool n = true;
    n.Foo();         // Object
    Ext.Foo( n );    // bool?
    Console.WriteLine();

    int m = 5;
    m.Foo();         // Object
    Ext.Foo( m );    // long 暗黙の数値変換
    Console.ReadKey();
  }
}

static class Ext
{
  public static void Foo( this long x ) { Console.WriteLine( "long" ); }
  //public static void Foo( this int x ) { Console.WriteLine( "int" ); }
  public static void Foo( this object x ) { Console.WriteLine( "Object" ); }
  public static void Foo( this short x ) { Console.WriteLine( "short" ); }
  //public static void Foo( this sbyte x ) { Console.WriteLine( "sbyte" ); }

  public static void Foo( this A x ) { Console.WriteLine( "A" ); }
  //public static void Foo( this B x ) { Console.WriteLine( "B" ); }

  public static void Foo( this bool? x ) { Console.WriteLine( "bool?" ); }
}

class A { public int Val; }

class B
{
  public int Val;

  public static implicit operator A( B b )
  {
    return new A { Val = b.Val };
  }
}

[] if ( 拡張メソッド == インスタンスメソッド ) return ?  if ( 拡張メソッド == インスタンスメソッド ) return ?を含むブックマーク  if ( 拡張メソッド == インスタンスメソッド ) return ?のブックマークコメント

前の記事を書いてからやっと気付いたけど(^^;、これはつまりインスタンスメソッドの動作をまねてるんですね。

もうちょっと調べてみました。ToString() の例はイマイチなので、別の例に差し替えます。

using System;

class Program
{
  static void Main()
  {
    B b = new B { Val = 1 };
    b.Foo();         // Object
    Ext.Foo( b );    // A

    //b.Baz();       // compile error!
    Ext.Baz( b );    // Ext.Baz( A )

    Console.ReadKey();
  }
}

static class Ext
{
  public static void Foo( this object x ) { Console.WriteLine( "Object" ); }
  public static void Foo( this A x ) { Console.WriteLine( "A" ); }
  //public static void Foo( this B x ) { Console.WriteLine( "B" ); }

  public static void Baz( A x ) { Console.WriteLine( "Ext.Baz( A )" ); }
}

class A
{
  public int Val;
  public void Baz() { Console.WriteLine( "A.Baz" ); }
}

class B
{
  public int Val;
  public static implicit operator A( B b ) { return new A { Val = b.Val }; }
}

b.Baz() だとコンパイルエラー。b が A 型に暗黙変換されないから。

Ext.Baz( b ) だと A 型に変換されるのでおっけい。

「引数」と「this になるもの」の変換規則は元々違ってた!

b.Baz() ってときの b の変換やその他の処理は「7.4.3 関数メンバの呼び出し」(MS の日本語仕様書の Ver1.2 を見てます)、7.3、7.5.5 ほか多数…。引数については「7.4.1 引数リスト」。やっぱり、それぞれ異なる変換規則があるようです。

「this になるもの」の変換規則は、前の記事で書いた拡張メソッドの1つめのパラメータの変換規則と同じようですね。正確なところはややこしすぎてわかりませんがw

結局、拡張メソッドがあらためてこの部分の変換規則の違いを浮き彫りにしたってのが正しいようです。そして拡張メソッドはこの違いをきちんと再現してるってことですね。でも、これヤヤコシイ。

[] 拡張メソッドの字面が引き起こす混乱  拡張メソッドの字面が引き起こす混乱を含むブックマーク  拡張メソッドの字面が引き起こす混乱のブックマークコメント

こちらは変換規則なんてややこしい問題ではないけど、字面が引き起こす混乱の例。

using System;

class P
{
  static void Main()
  {
    S a = new S { Val = 0 };
    Console.WriteLine( a.Val ); // 0

    a.Inc();
    Console.WriteLine( a.Val ); // 1

    a.ExtInc();
    Console.WriteLine( a.Val ); // 1

    Ext2.ExtInc( a );
    Console.WriteLine( a.Val ); // 1

    a = a.ExtInc2();
    Console.WriteLine( a.Val ); // 2

    a = Ext2.ExtInc2( a );
    Console.WriteLine( a.Val ); // 3

    Console.WriteLine();


    C c = new C { Val = 0 };
    Console.WriteLine( c.Val ); // 0

    c.Inc();
    Console.WriteLine( c.Val ); // 1

    c.ExtInc();
    Console.WriteLine( c.Val ); // 2

    Ext2.ExtInc( c );
    Console.WriteLine( c.Val ); // 3

    c = c.ExtInc2();
    Console.WriteLine( c.Val ); // 4

    c = Ext2.ExtInc2( c );
    Console.WriteLine( c.Val ); // 5

    Console.ReadKey();
  }
}

struct S
{
  public int Val;
  public void Inc() { this.Val++; }
}

class C
{
  public int Val;
  public void Inc() { this.Val++; }
}

static class Ext2
{
  public static void ExtInc( this S a ) { a.Val++; }
  public static S ExtInc2( this S a ) { a.Val++; return a; }

  public static void ExtInc( this C a ) { a.Val++; }
  public static C ExtInc2( this C a ) { a.Val++; return a; }
}

値型を引数に取って値を変更する拡張メソッドは、イヤラシイ。

説明不要ですよね。え、なんで?と思ってしまった方は、一息ついてから考えればアハ体験できるハズ。

NyaRuRuNyaRuRu 2007/11/22 04:11 値型に対する (破壊的) 拡張メソッドですが,Visual Basic だと第一引数を byref にでき,C# だとできない,という話があります.
CLR の引数渡し方法に,AsThis みたいなのを正式に導入しておけばよかったんですけどねぇ.

http://blogs.msdn.com/vbteam/archive/2007/01/18/extension-methods-part-3.aspx
http://blogs.msdn.com/sreekarc/archive/2007/04/25/extension-methods.aspx

siokoshousiokoshou 2007/11/22 07:16 AsThis っていいですねぇ。VB の byref な拡張メソッドを C# で呼ぶとどうなるんだろう…。

NyaRuRuNyaRuRu 2007/11/22 09:40 >。VB の byref な拡張メソッドを C# で
まえに試してみたんですが,インスタンスメソッドの構文では見えなくなる (呼べない) ようでした.
静的メソッドとして呼ぶのはもちろん OK と.

siokoshousiokoshou 2007/11/22 16:28 そうなんですか。拡張メソッド、仕様書にはたいしたことは書いてないけど細々と地雷が仕掛けてありますね(^^;

トラックバック - http://d.hatena.ne.jp/siokoshou/20071121

2007/11/20 (火)

[] VS2008  VS2008を含むブックマーク  VS2008のブックマークコメント

あちこちで書かれてて、今さらですが出ましたね。

http://msdn2.microsoft.com/en-us/vstudio/products/aa700831.aspx

.NET3.5 やソースコードLINQWPF やらと賑やかですが、実は一番期待しているのは WinForm のデザイナがエラーを吐かないようになったかな?というところだったり(^^; できるかな?また無理なのかな…?言語やライブラリには概ね満足ですが、VisualStudio は…だったのでよくなってるといいな。

トラックバック - http://d.hatena.ne.jp/siokoshou/20071120

2007/11/13 (火)

[] EqualityComparer<T> を覗いてみる  EqualityComparer<T> を覗いてみるを含むブックマーク  EqualityComparer<T> を覗いてみるのブックマークコメント

EqualityComparer<Foo>.Default とかすると比較子が取れるなんとも不思議なクラスですが、こんなふうになってるんですね(monoです)。自身を継承したクラスを強引に作ってる(^^;

Equals メソッドで T のオブジェクトが null か判定しています。この部分は IL には box 化して null と比較するコードが出てきます。T が値型の場合は、リッチャー本(プログラミングMS .NET FRAMEWORK 第2版 (マイクロソフト公式解説書))によれば JIT コンパイラが比較処理を取り除いてしまうそうです。 struct 制約をつけると null との比較はコンパイルエラーになります。賢いんだけど、ややこしいですねぇ。

[] C# の親たち  C# の親たちを含むブックマーク  C# の親たちのブックマークコメント

http://blogs.msdn.com/charlie/archive/2007/11/12/visual-c-team-picture-fall-2007.aspx

id:siokoshou:20071111:p1 を貼っておいて、こっちを取り上げないわけにはいかないなっと。完成記念の集合写真でしょうか。blog でいつも読んでる方々のお顔が見れるのがうれしぃ。

最近の C# チームの blog の注目は Eric Lippert さんのジェネリクスの共変と反変でしょうか。ネイティブな英語と高度な話題で読むのがとても難しい…。キリンとか亀とかやめて欲しいw

NyaRuRuNyaRuRu 2007/11/14 02:20 >EqualityComparer<Foo>.Default
http://d.hatena.ne.jp/NyaRuRu/20070216/p1
で紹介したこの辺も読むと歴史的経緯が分かっておもしろいかもしれません.
http://blogs.msdn.com/bclteam/archive/2005/03/15/396483.aspx

こっちが Krzysztof Cwalina さんの blog
http://blogs.msdn.com/kcwalina/

siokoshousiokoshou 2007/11/14 14:02 これはいい解説ですね。じっくり読んでみます。
このあたり、短いのにトリック満載でおもしろいコードですよね。

トラックバック - http://d.hatena.ne.jp/siokoshou/20071113

2007/11/11 (日)

トラックバック - http://d.hatena.ne.jp/siokoshou/20071111

2007/11/9 (金)

[] Win32manifest  Win32manifestを含むブックマーク  Win32manifestのブックマークコメント

http://msdn2.microsoft.com/ja-jp/library/bb545961(VS.90).aspx

manifestがつけれるようになるみたい。

#読みづらいので修正。

[] アヒルのように飛び…  アヒルのように飛び…を含むブックマーク  アヒルのように飛び…のブックマークコメント

http://www.popfly.ms/users/siokoshou/NASA

popflyってみた。はまりそう。ちょっと重いけど。なぜかときどき表示されないこともあるけれど、おもちゃのアヒルなので。

トラックバック - http://d.hatena.ne.jp/siokoshou/20071109

2007/11/8 (木)

[] Visual Studio 高速化  Visual Studio 高速化を含むブックマーク  Visual Studio 高速化のブックマークコメント

via http://weblogs.asp.net/scottgu/archive/2007/11/01/tip-trick-hard-drive-speed-and-visual-studio-performance.aspx

長いのでほとんど読んでませんが(^^;、よいハードを使えば速くなるよと。特にハードディスクの効果が大きいよと。価格.comでノート用の2.5インチ7200rpmドライブを眺めてみたら、ずいぶんと安くなってますね。VisualStudio2008にあわせて入れ替えようか、それともいっそPC新調か迷うところ。

本題はそこからリンクされてるこっち。見ればわかると思うので訳さないけど。

スタートページを切ると起動がかなり速くなりました。下のほうはあまり従っていないので効果はちょっとわかりません。

#こうしてtipsをネットに出して環境入れ替え準備を着々と…

トラックバック - http://d.hatena.ne.jp/siokoshou/20071108

2007/11/5 (月)

[] デバッグ技 : .ini ファイルによる JIT コンパイラ制御  デバッグ技 : .ini ファイルによる JIT コンパイラ制御を含むブックマーク  デバッグ技 : .ini ファイルによる JIT コンパイラ制御のブックマークコメント

NyaRuRuさんが書いていた 64bit CLR の話とほとんどかぶっているネタですが、JIT コンパイラを制御するデバッグ技が紹介されていたので勝手に抜粋翻訳。

via Scott Hanselman's ComputerZen.com

Release IS NOT Debug: 64bit Optimizations and C# Method Inlining in Release Build Call Stacks

関連ネタ

話の発端は、リリースビルドとデバッグビルドで例外時のスタックトレースの結果が違うこと。

using System;

class NormalProgram
{
  static void Main(string[] args)
  {
    try
    {
      methodA();
    }
    catch (System.Exception e)
    {
      Console.WriteLine(e.ToString());
    }
  }
  static void methodA() { methodB(); }
  static void methodB() { methodC(); }
  static void methodC() { badMethod(); }
  static void badMethod() { throw new ApplicationException("generic bad thing"); }
}

デバッグビルドとリリースビルドでこれを作って実行してみます。まずはデバッグビルドの 32bit版。

System.ApplicationException: generic bad thing
   場所 NormalProgram.badMethod() 場所 ...\Program.cs:行 19
   場所 NormalProgram.methodC() 場所 ...\Program.cs:行 18
   場所 NormalProgram.methodB() 場所 ...\Program.cs:行 17
   場所 NormalProgram.methodA() 場所 ...\Program.cs:行 16
   場所 NormalProgram.Main(String[] args) 場所 ...\Program.cs:行 9

きれいにトレースが取れています。ところで、英語版だと最初の「場所」が at で、真ん中の「場所」が in なんですねw 翻訳してくれないほうがよかったようなw

一方、リリースビルドの 32bit では、

System.ApplicationException: generic bad thing
   場所 NormalProgram.badMethod() 場所 ...\Program.cs:行 19
   場所 NormalProgram.Main(String[] args) 場所 ...\Program.cs:行 9

こうなってしまう。最適化による影響です。

次にインライン化を抑制してみます。

using System;
using System.Runtime.CompilerServices;

class NormalProgram
{
  [MethodImpl( MethodImplOptions.NoInlining )]
  static void Main( string[] args )
  {
    try
    {
      methodA();
    }
    catch ( System.Exception e )
    {
      Console.WriteLine( e.ToString() );
    }
  }
  [MethodImpl( MethodImplOptions.NoInlining )]
  static void methodA() { methodB(); }
  [MethodImpl( MethodImplOptions.NoInlining )]
  static void methodB() { methodC(); }
  [MethodImpl( MethodImplOptions.NoInlining )]
  static void methodC() { badMethod(); }
  static void badMethod() { throw new ApplicationException( "generic bad thing" ); }
}

32bit リリースビルドを実行すると

System.ApplicationException: generic bad thing
   場所 NormalProgram.badMethod() 場所 ...\Program.cs:行 24
   場所 NormalProgram.methodC() 場所 ...\Program.cs:行 23
   場所 NormalProgram.methodB() 場所 ...\Program.cs:行 21
   場所 NormalProgram.methodA() 場所 ...\Program.cs:行 19
   場所 NormalProgram.Main(String[] args) 場所 ...\Program.cs:行 11

インライン化が抑止でき、スタックトレースが完全に取れました。今度は 64bit リリースで実行します。x64 環境がないので(T^T)ここは試してません。

System.ApplicationException: generic bad thing
   at NormalProgram.methodC() in NormalProgram.cs:line 23
   at NormalProgram.Main(String[] args) in NormalProgram.cs:line 11

インライン抑止属性は無視されてしまいました。64bit CLR は積極的にインライン化します。インライン化の例というより、末尾最適化の例です。


じゃあ、完全なスタックトレースを取るにはどうしたらよいか?悪い例を3つ挙げてますが省略。

良い方法は .ini ファイルによる [.NET Framework Debugging Control] セクションを使うことです。この JIT 構成には、2つの面があります。

  • JIT コンパイラに追跡情報を生成させることができます。これは、デバッガが MSIL と対応する機械語をマッチさせ、ローカル変数と関数の引数がどこに保存されるか追跡できるようにします。
  • JIT コンパイラに、機械語の最適化を止めさせることができます。

Foo.exe があるなら Foo.ini として

[.NET Framework Debugging Control]
GenerateTrackingInfo=1
AllowOptimize=0

と書いておくと、完全なスタックトレースが取れます!32bit リリースビルドで確認してみました。確かに完全なトレースが取れました。64bit は試してません。

これはリリースファイル作成時に /debug:pdbonly をつけてコンパイルしてあることを前提としているそうです。これはデバッグ向けの機能です(原文でしつこく念押ししているので書いておきます)。

こちらも参考に。

http://www.hanselman.com/blog/DebugVsReleaseTheBestOfBothWorlds.aspx

(追記) http://msdn2.microsoft.com/ja-jp/library/9dd8z24x(VS.80).aspx

2007/11/4 (日)

[] XmlSerializer の実行時コード生成を止める方法  XmlSerializer の実行時コード生成を止める方法を含むブックマーク  XmlSerializer の実行時コード生成を止める方法のブックマークコメント

id:siokoshou:20071103:p2 の続き。

List<T> を使ってたのをやめて配列にしてみたけど、やっぱりコードの自動生成&コンパイルは止まりません。しょうがないので、もう一度 WinDbg で止めて生成したコードを眺めてみると、ArrayOfHoge という、ユーザ定義 Hoge クラスの配列を扱うコードが生成されてました。id:shiba-yan さんに教えてもらった sgen /k を使って、/a でアセンブリのすべての型への XmlSerializer コードを出してみると、Hoge[] が含まれていません。そりゃそうだよね、全部の型に対して配列の分も用意してたら大変なことになるし。

MS 製 sgen の問題

それじゃあ、sgen に Hoge[] を出してもらおうとしたら…。/t オプションで型を指定できるんですが、一つしか認識してくれないようです…。2つの型のコードを出したいんです!それも /a では出てこないやつも含めて。吐き出されたコードを手作業でマージする手もあるけど、ここはなんとか自動化したいところ。

ぐぐってみると、同じ問題にぶつかってる人が既にいました。投稿者さんは MS から sgenplus という別のツールをもらったようですが、mono の sgen なら複数の型に対応してるよって情報も。試しに mono の sgen を使ってみました。

http://anonsvn.mono-project.com/viewcvs/trunk/mcs/tools/sgen/

mono の sgen の問題とその修正

mono の sgen はそのまま MS.NET 環境で動きました。/t が複数あればきちんと複数の型に対するコードが出てきました!が、こちらはこちらで配列に対応してませんでした…。/t:Hoge[] だとコードが出てきません。でも、試しにちょっとコードをいじってみたら、簡単に直ってしまいました。やっぱコードが公開されてることは重要ですね。助かります。sgen 自体はたいしたことはしてなくて、型をパラメータとして渡してやればあとは .NET の内部でゴソゴソしてくれるようです。

これで生成した Fuga.XmlSerializers.dll を実行ファイルと同じディレクトリに置いて、Filemon で見ながら実行してみると、遂にコード生成なしで動きました!めでたし!長かった。

その後、mono の sgen を id:atsushieno さんに協力していただいて登録してもらえました。ありがとうございます!オリジナルの sgen が実は /t なしだと MS.NET 環境で例外を出すという別の問題にぶつかったりもしたんですが、そちらもついでに直しました。ものすごいちっちゃい修正ですが(^^;

というわけで、XmlSerializer のコード自動生成でデッドロックや遅さにお困りの方は mono の sgen を試してみてください。デッドロック回避の WinXP のパッチも出てますが、ユーザに入れてという訳にはいかない場合にどうぞ。

自動生成してるかどうかは Filemon で確認できます。Filter の Exclude に普段から I/O してるプロセス名を登録しまくってマスクして、検索で「.cs」を探すと楽です。F3 で次の検索、Shift+F3 で逆方向へ検索もできます。

結局、VisualStudio の「シリアル化アセンブリの生成」はよくわからないままでしたw

mayukimayuki 2007/11/05 01:09 > シリアル化アセンブリの生成
これはWSDLとかのWeb参照で使う内部のシリアライズクラスを先にコンパイルしておくことができる機能ですね。

siokoshousiokoshou 2007/11/05 17:14 そうなんですか。XmlSerializer を使うシナリオ全般で有効なのかと思わせる名前だけど、実はそうじゃないんですね。ヘルプの情報が少なすぎて、さっぱりわからず自分の環境が壊れてるのかと思って、もう少しで再インストールするところでした(^^;
情報ありがとうございます。

2007/11/3 (土)

[] XmlSerializer が生成したコードを取得してみた  XmlSerializer が生成したコードを取得してみたを含むブックマーク  XmlSerializer が生成したコードを取得してみたのブックマークコメント

.NET で XML の読み書きするのに一番簡単なのはおそらく XmlSerializer。でも、こいつは自動でコードを生成して、コンパイルして、やっと読み書きができるので遅いのが難点です。これでも早くしたそうなので、昔はリフレクションしてたのかな?ついでに日本語版 WinXP だとデッドロックする欠点があるそうです。

ビルドの設定で「シリアル化アセンブリの生成」ってのがあるけど、これの意味がわかりません。オンにしても SGen.exe で作られる Hoge.XmlSerializers.dll が生成されたためしがありません…。もし生成できたら、自動コード生成とコンパイルの部分がいらなくなるの?このあたり、さっぱりわかってないので調べてみないと…。

で、このデッドロックや遅さに最近悩まされてて、どうにかしようとしてます。その過程でこいつが生成するコードに興味がわいてきてしまって、なんとか生成したコードを読めないかとチャレンジしてみました。

もっと簡単な方法がありそうだけど、思いつかなかったのでかなり面倒なことをしました。簡単な方法を思いついた方はコメントください。お待ちしております。

最初はデバッガで止めながら、FileMon でファイルがいつ生成されてるのかを調べてたんだけど、XmlSerializer( type ) を new すると、その中で hoge.cs を吐いてコンパイルして削除まで一気にしてしまうことがわかりました。これじゃあ、cs ファイルは横取りできません。

それなら、ファイル削除のとこで実行を止めちゃえばイイジャンってことで、WinDbg の出番です。ちょっと話がオオゲサになってきました。

まずは、dumpbin /exports C:\Windows\system32\kernel32.dll で DeleteFileW を探します。で、WinDbg で実行ファイルを読み込み、一度実行して適当なところで止めて、kernel32 の DeleteFileW のアドレスを探します。kernel32.dll モジュールの先頭 + さっき調べた DeleteFileW のエントリポイントのアドレスに bp コマンドでブレークを張ります。あとはリスタートすれば、(ほかにファイル削除を使っていなければ)ブレークに止まったときに個人の tmp ディレクトリに XmlSerializer が吐いたコードがあります!

手間を掛けたわりに、読んだところで「で?」っていうコードでした(^^; ここだけ読んでもしょうがないですね。

すべて MS が配っているモノしか使ってないハックでした。

[] XmlSerializer をもうちょっと  XmlSerializer をもうちょっとを含むブックマーク  XmlSerializer をもうちょっとのブックマークコメント

XmlSerializer を数箇所で使ってて、Hoge.XmlSerializers.dll を用意してやる前は起動時に2つコードを生成してました。 SGen で Hoge.XmlSerializers.dll を用意してやったらこれがなくなるハズ、だったんですがまだ一つ生成してます…。もしかしたら XmlSerializer で「ArrayList と List<T> をシリアル化できない」って制限を無視して使っているのが原因かも。使ってみたらできたんで、つい…。

shiba-yanshiba-yan 2007/11/03 01:03 Sgen で /k オプションを付けると、アセンブリと同じ場所に生成されたコードが残ったままになりますよ。
これが XmlSerializer で自動的に作られるものと同じなのかはわかりませんが。
http://msdn2.microsoft.com/ja-jp/library/bk3w6240(VS.80).aspx

siokoshousiokoshou 2007/11/03 01:40 お〜、コードも取れました。ありがとうございます!
この苦労はいったい…w

siokoshousiokoshou 2007/11/03 01:54 以前はデッドロックなんて起きていなかったような気がするんですが、もしかしてこいつらが関係している?↓
http://www.microsoft.com/japan/technet/security/bulletin/MS07-040.mspx
http://support.microsoft.com/kb/941349/ja

2005 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 06 | 09 | 11 | 12 |
2007 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 08 | 09 | 10 | 12 |
2009 | 01 | 03 | 04 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 07 |
2011 | 04 | 07 | 10 |
2012 | 04 | 12 |
2013 | 08 |
2014 | 03 | 08 |
2017 | 09 |