none
OSによるリフレクション動作の違いについて RRS feed

  • 質問

  • リフレクションにより取得できるプロパティで、XP と 7(64bit)において、動作に違いがありました。

    下記、コードを実行したところ、.NET 3.5でのWindow7(64bit)環境では、protectedなA.Itemが取得できませんでした。

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Reflection;
    using System.Diagnostics;
    
    namespace ConsoleApplication1
    {
    	class Program
    	{
    		static void Main(string[] args)
    		{
    			Print(typeof(B));
    
    			Console.ReadLine();
    		}
    
    		private static void Print(Type t)
    		{
    			Console.WriteLine(t.FullName);
    
    			foreach (PropertyInfo info in t.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
    				Console.WriteLine("{0}\t{1}", info.Name, info.DeclaringType.FullName);
    				Debug.Print("{0}\t{1}", info.Name, info.DeclaringType.FullName);
    			}
    
    			Console.WriteLine();
    		}
    
    		private class A<T>
    		{
    			protected virtual T this[int no]
    			{
    				get { return default(T); }
    			}
    		}
    
    		private class B : A<int>
    		{
    			public new int this[int no]
    			{
    				get { return base[no]; }
    			}
    		}
    	}
    }
    

    実行結果。

    .NET 3.5 Windows7(64bit)

    Item ConsoleApplication1.Program+B

    (protectedが取得されない)

    .NET 3.5 XP/Vista(32bit)

    Item ConsoleApplication1.Program+B

    Item ConsoleApplication1.Program+A`1[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]

    .NET 4.0 XP/7(64bit)

    Item ConsoleApplication1.Program+B

    Item ConsoleApplication1.Program+A`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]

     

    なお、コードはVS2010で作成(x86指定)しており、VS2008でも同様の結果となりました。

    また、作成したexeでも同様の結果となったため、.NET Frameworkの問題と考えています。

    元の問題が出たコードの再現としたため、インデクサとなっていますが、通常のプロパティでも同一の結果となりました。

    なお、ジェネリックな場合だけであり、通常のクラスからの派生の場合はそもそも、オーバーライドされたプロパティは取得されないようです。

     

    なにか情報をお持ちの方はいらっしゃいませんでしょうか?

    また、どなたか追試を行っていただけたら幸いです。


     

    • 編集済み Y-Y 2010年5月27日 5:38 追記
    2010年5月27日 1:44

回答

  • こちらで Vista(32bit .NET3.5) と 7(64bit 既定) で試した結果も同じでした。

    "Generic Reflection protected Windows 7" のキーワードで検索したところ、
    Y-Y さんのこのスレッドが1件目に見つかって、
    その関連ページとして以下のページが2番目にありました。

    Reflection problem - generic types and inheritance
    http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/701316e1-97e0-4390-9c8b-b30cc0ba54eb

    こちらは virtual と override の関係のようですが、ジェネリックが関係した場合の話のため無関係ではないように思ったのと、最後の人が紹介されているリンク先(マイクロソフトの人のブログ)が参考になるかもしれないと思い、(私はまだ理解できていないのですが)紹介だけさせてもらいます。

    追記:
    リンク先の virtual と override の話としては、そもそも2つ(virtual 側も)表示されることが正しくないということのようですね。
    メソッドでは確かに override 側しか表示されません。

    それを考えると、new による隠ぺいであっても同じかと思ったのですが、何点かおかしいですね。

    ・メソッドの new による隠ぺいでは、元のものも取得できる(override とは異なる)。
    ・.NET 4.0 では修正されていない(最終的に互換性を優先?)。
      ↑訂正:virtual と override については、修正されていました(4.0では結果が変わる)。
    ・Windows 7 の .NET 3.? だけ違う。

    • 編集済み TH01 2010年5月27日 8:50 訂正
    • 回答としてマーク Y-Y 2010年5月27日 9:35
    2010年5月27日 7:33

すべての返信

  • 32bit に限定しているため、Win7 + .NET 3.5 環境では実行ポリシーが違うのではないでしょうか?結果として、CAS の制約を受けて取得できるプロパティ量に変化があるのではないかと思います。(つまり、仕様通りの動作)

    ビルドを CPU 非依存にするか、実行ポリシーを編集することが必要ではないでしょうか。(.NET 4.0 で再現しないのは、CAS 関連の見直しで実行ポリシーのデフォルト値が変更されているからでしょう)

    2010年5月27日 3:55
  • 返信ありがとうございます。

    32bit に限定しているため、Win7 + .NET 3.5 環境では実行ポリシーが違うのではないでしょうか?結果として、CAS の制約を受けて取得できるプロパティ量に変化があるのではないかと思います。(つまり、仕様通りの動作)

    ビルドを CPU 非依存にするか、実行ポリシーを編集することが必要ではないでしょうか。(.NET 4.0 で再現しないのは、CAS 関連の見直しで実行ポリシーのデフォルト値が変更されているからでしょう)

    不勉強なため、CAS周りに関してはあまり考えていませんでした。

    リフレクションに関するセキュリティ上の考慮事項(http://msdn.microsoft.com/ja-jp/library/stfy7tfc(v=VS.100).aspx)あたりの話でよろしいでしょうか?

    まだ、どう変更して試せば良いか、理解出来ていませんが…。

     

    なお、ビルドをCPU非依存(AnyCPU)、および、x64では試してみましたが、状況は変わりませんでした。

    また、Vista(32bit)ではXPと同じ結果でした。

    2010年5月27日 5:25
  • こちらで Vista(32bit .NET3.5) と 7(64bit 既定) で試した結果も同じでした。

    "Generic Reflection protected Windows 7" のキーワードで検索したところ、
    Y-Y さんのこのスレッドが1件目に見つかって、
    その関連ページとして以下のページが2番目にありました。

    Reflection problem - generic types and inheritance
    http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/701316e1-97e0-4390-9c8b-b30cc0ba54eb

    こちらは virtual と override の関係のようですが、ジェネリックが関係した場合の話のため無関係ではないように思ったのと、最後の人が紹介されているリンク先(マイクロソフトの人のブログ)が参考になるかもしれないと思い、(私はまだ理解できていないのですが)紹介だけさせてもらいます。

    追記:
    リンク先の virtual と override の話としては、そもそも2つ(virtual 側も)表示されることが正しくないということのようですね。
    メソッドでは確かに override 側しか表示されません。

    それを考えると、new による隠ぺいであっても同じかと思ったのですが、何点かおかしいですね。

    ・メソッドの new による隠ぺいでは、元のものも取得できる(override とは異なる)。
    ・.NET 4.0 では修正されていない(最終的に互換性を優先?)。
      ↑訂正:virtual と override については、修正されていました(4.0では結果が変わる)。
    ・Windows 7 の .NET 3.? だけ違う。

    • 編集済み TH01 2010年5月27日 8:50 訂正
    • 回答としてマーク Y-Y 2010年5月27日 9:35
    2010年5月27日 7:33
  • TH01さん、情報ありがとうございます。 症状としては、ビンゴのようです。

    結論は…、ざっと見る限りでは若干釈然としないのでもう少しよく読んでみます(英語は苦手なので正しく解釈できているか不安…)。

    こちらで Vista(32bit .NET3.5) と 7(64bit 既定) で試した結果も同じでした。


    同じというのは、どちらも、ジェネリックの基本クラスのプロパティも取得できたと言う意味でしょうか?

    それとも、私の試した環境と同じ結果(Vistaと7で異なる結果)と言う意味でしょうか?

    お手数ですが、よろしければ返信ください。、

    2010年5月27日 8:33
  • すみません、どちらにもとれますね。
    Y-Yさんと同じで、Vista と 7 で結果が異なりました。

    それと、先の私の返信の追記部分の
    ・.NET 4.0 では修正されていない
    は、virtual と override の関係についてはまだ調べられていなかったので、修正されていないかどうかはこれから調べようと思っています。(調べられたら上の返信を修正するつもりです。)
    →しました。
    2010年5月27日 8:42
  • 情報を整理して、再検証してみました。

     

    OS(.NET) override new
    XP(3.5) 重複 重複
    7(3.5) 派生のみ 派生のみ
    XP/7(4.0) 派生のみ 重複

     

    OSと、.NETのバージョンの組み合わせによって、結果が違うようです。

     

    参考URL

     

    Reflection problem - generic types and inheritance

    http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/701316e1-97e0-4390-9c8b-b30cc0ba54eb

     

    Override properties (III): Type.GetProperties

    http://blogs.msdn.com/b/weitao/archive/2009/06/03/override-properties-iii-type-getproperties.aspx


    上記、URLの流れですと、.NET 3.5での、Windows7より前の動作はバグだから7で修正したよ、というように取れるのですが、
    7(3.5)で重複した結果を返さなかった new は、.NET4.0では重複した結果を返すようです(これで正解な気がする)。

    情報提供、および、検証をしてくださった方々、ありがとうございました。


    しかし、重複した結果を返すことを期待した実装をしてるんだよなぁ…

    2010年5月27日 9:34
  • 最終的に検証に使用したコードを載せておきます。

     

    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Reflection;
    using System.Diagnostics;
    
    namespace ConsoleApplication1
    {
    
    	class Program
    	{
    		static void Main(string[] args)
    		{
    			Print(typeof(B));
    
    			Console.ReadLine();
    		}
    
    		private static void Print(Type t)
    		{
    			Console.WriteLine(t.FullName);
    
    			foreach (PropertyInfo info in t.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
    				Console.WriteLine("{0}\t{1}", info.Name, info.DeclaringType.FullName);
    				Debug.Print("{0}\t{1}", info.Name, info.DeclaringType.FullName);
    			}
    
    			Console.WriteLine();
    		}
    
    		private class A<T>
    		{
    			public virtual T Value1
    			{
    				get { return default(T); }
    			}
    			public virtual T Value2
    			{
    				get { return default(T); }
    			}
    			public virtual T Value3
    			{
    				get { return default(T); }
    			}
    		}
    
    		private class B : A<int>
    		{
    			public override int Value1
    			{
    				get
    				{
    					return base.Value1;
    				}
    			}
    			public new int Value2
    			{
    				get
    				{
    					return base.Value1;
    				}
    			}
    		}
    	}
    }
    

    2010年5月27日 9:39
  • 結構難しいい問題ですね、手元ですぐに試せればいいんですが、

    メタデータ仕様をちゃんと覚えてないのですが、newslot がプロパティに指定された場合に、対応した get/set  のメソッド以外に、プロパティ自身のメタデータがどのように格納されているとみなすかって問題みたいですね。

    # .NET 3.5+Win7 において、typeof(A<int>) と typeof(B) から取得される PropertyInfo の
    # GetGetMethod() が違うものを返せば「仕様があいまいだった」といわれても私は文句ないですが... 

    > しかし、重複した結果を返すことを期待した実装をしてるんだよなぁ…

    英語のフォーラムにあるように、GetMethod と SetMethod の newslot の扱いについては差がないということなので、そちらをベースに判定されるとよいのではないでしょうか。

     

    2010年5月28日 3:55