QA@IT

C#(Mono)のObject.GetType()の呼び出しの有無で挙動が変わる?

7487 PV

C#で以下のようなコードを書いていますが、実際にMono上で動かすとObject.GetType()を呼び出すかどうかで挙動が変わってしまい困っています。

// tmp.cs
using System;
using System.Reflection;

namespace Tmp
{
  public class Packer
  {
    public Packer()
    {
    }

    public void PackUInt16(ushort value)
    {
    }

    public void PackInt16(short value)
    {
      //value.GetType();
      Console.WriteLine("value({0}) <  -0x80 => {1}", value, value < -0x80);
      Console.WriteLine("value({0}) <  -0x20 => {1}", value, value < -0x20);
      Console.WriteLine("value({0}) <   0x80 => {1}", value, value < 0x80);
      Console.WriteLine("value({0}) <  0x100 => {1}", value, value < 0x100);
    }

    public void PackObject<T>(T obj)
    {
      Type this_type = this.GetType();
      string obj_type_name = obj.GetType().ToString();
      string method_name = "Pack" + obj_type_name.Substring(obj_type_name.LastIndexOf(".") + 1);
      MethodInfo mi = this_type.GetMethod(method_name);
      mi.Invoke(this, new object[] { obj });
    }

    public static void Main()
    {
      Packer packer = new Packer();
      packer.PackObject((ushort)0);
      packer.PackObject((short)-1);
    }
  }
}

上記Tmp.Packer.PackUInt16()に-1以下の値を渡すと、そのメソッド内に書かれている条件式の結果がすべて偽(False)になります。

value(-1) <  -0x80 => False
value(-1) <  -0x20 => False
value(-1) <   0x80 => False
value(-1) <  0x100 => False

ただし、上記でコメントアウトしているvalue.GetType()を有効にするか、Tmp.Packer.Main()packer.PackObject((ushort)0);をコメントアウトすれば、正しい結果を得られます。

value(-1) <  -0x80 => False
value(-1) <  -0x20 => False
value(-1) <   0x80 => True
value(-1) <  0x100 => True

これは正しい挙動でしょうか? もしくはMonoの不具合か、私のコードがまずいのでしょうか?

なお、上記挙動は主にMac OS X 10.7.5上で、Monoの公式サイトからダウンロードしたMono 3.0.6で確認したものです。

% uname -mprs ; mono -V
Darwin 11.4.2 x86_64 i386
Mono JIT compiler version 3.0.6 (master/20e40c4 Wed Feb 27 10:15:23 EST 2013)
Copyright (C) 2002-2012 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
    TLS:           normal
    SIGSEGV:       altstack
    Notification:  kqueue
    Architecture:  x86
    Disabled:      none
    Misc:          softdebug 
    LLVM:          yes(3.1svn-mono)
    GC:            Included Boehm (with typed GC)

また、FreeBSD 9.1-STABLEにインストールしたMono 3.0.7でも同じ結果が得られることを確認済みです。

% uname -mprs ; mono -V                                                            
FreeBSD 9.1-STABLE amd64 amd64
Mono JIT compiler version 3.0.7 ((no/514fcd7 2013年 4月 5日 金曜日 15時29分23秒 JST)
Copyright (C) 2002-2012 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
        TLS:           __thread
        SIGSEGV:       normal
        Notification:  kqueue
        Architecture:  amd64
        Disabled:      none
        Misc:          softdebug 
        LLVM:          supported, not enabled.
        GC:            Included Boehm (with typed GC and Parallel Mark)

2013-04-20追記
この件をMonoの不具合として以下のように開発側に報告し、無事修正されましたので追記しておきます。
https://bugzilla.xamarin.com/show_bug.cgi?id=11750
https://bugzilla.xamarin.com/show_bug.cgi?id=11862
おそらく次回リリース時(3.0.10 と 2.10.12 か)では修正されていると思います。

回答

コメントにも書きましたがVisual Studioから試してみました。

VS2008, VS2010, VS2012
VS2008はターゲットフレームワーク 2.0でも確認
2010と2012は x86とx64でも確認

全て

value(-1) <  -0x80 => False
value(-1) <  -0x20 => False
value(-1) <   0x80 => True
value(-1) <  0x100 => True

となりましたので、やはり Monoの不具合ではないかと思います。

-追記-
確認コードは最初に提示されたコードそのまま使いました。
value.GetType()もコメントアウトされていて 引数 (uhort)0 での呼び出しもあります)。
プロジェクトはコンソールアプリケーションです。
OSはWin7 (VS2008,VS2010)とWin8 (VS2012)

編集 履歴 (1)
  • ご確認ありがとうございます。Visual Studioでは再現しないことがわかって良かったです。 -
  • Monoの現時点の最新(add213568839cd58105b3540e27036edf1954d7f)でも同じ結果が得られましたので、のちほどMonoへバグ報告することにしました。ひとまずこの質問は解決とします。ありがとうございました。 -
  • すみません、記録として一応ビルドしたcommitへのリンクを書いておきます。 https://github.com/mono/mono/commit/add213568839cd58105b3540e27036edf1954d7f -
  • 確認おつかれさまです。monoと.NETにも差分があるんですね、勉強になりました。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。