トップ回答者
OSによるリフレクション動作の違いについて

質問
-
リフレクションにより取得できるプロパティで、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 追記
回答
-
こちらで 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.? だけ違う。
すべての返信
-
返信ありがとうございます。
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と同じ結果でした。
-
こちらで 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.? だけ違う。 -
-
情報を整理して、再検証してみました。
OS(.NET) override new XP(3.5) 重複 重複 7(3.5) 派生のみ 派生のみ XP/7(4.0) 派生のみ 重複 OSと、.NETのバージョンの組み合わせによって、結果が違うようです。
参考URL
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/701316e1-97e0-4390-9c8b-b30cc0ba54eb
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では重複した結果を返すようです(これで正解な気がする)。
情報提供、および、検証をしてくださった方々、ありがとうございました。
しかし、重複した結果を返すことを期待した実装をしてるんだよなぁ…
-
最終的に検証に使用したコードを載せておきます。
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; } } } } }
-
結構難しいい問題ですね、手元ですぐに試せればいいんですが、
メタデータ仕様をちゃんと覚えてないのですが、newslot がプロパティに指定された場合に、対応した get/set のメソッド以外に、プロパティ自身のメタデータがどのように格納されているとみなすかって問題みたいですね。
# .NET 3.5+Win7 において、typeof(A<int>) と typeof(B) から取得される PropertyInfo の
# GetGetMethod() が違うものを返せば「仕様があいまいだった」といわれても私は文句ないですが...> しかし、重複した結果を返すことを期待した実装をしてるんだよなぁ…
英語のフォーラムにあるように、GetMethod と SetMethod の newslot の扱いについては差がないということなので、そちらをベースに判定されるとよいのではないでしょうか。