2010-11-20 8 views
1

次のコードでは、ランタイムのデステージビリティが発生する可能性があるという例外が発生します。 Opcodes.CallVirtへOpcodes.Callを変更なぜコール命令がランタイムのデステージビリティをもたらすのですか?

var method = new DynamicMethod("CallObjectToString", typeof(string),new[]{ typeof(object)}); 
var ilgen =method.GetILGenerator(); 
ilgen.Emit(OpCodes.Ldarg_0); 
ilgen.Emit(OpCodes.Call, typeof(object).GetMethod("ToString")); 
ilgen.Emit(OpCodes.Ret); 
var @delegate = method.CreateDelegate(typeof(Func<object, string>)) as Func<object,string>; 
@delegate(new object()); 

は、問題を修正します。 これはすべてうまくできていますが、typebuilderを使用して、という正確なのILを持つ(MethodBuilder)を使用して構築された静的メソッドを作成し、CreateDelegateを使用してこの例外をスローしません。実際にはメソッドビルダーを使って、型が継承しているものではなく、まったく別のオブジェクトの仮想メソッドで何かを呼び出すことができます。さらに不可解私はnew object().ToString()ような何かを行う場合、それはまた、むしろcallvirtよりも、ILにcall命令を発することは何

callを使用して仮想メソッドを呼び出すことは無効ですが、インスタンスのオーバーライドで基本メソッドを呼び出す場合を除いて、CLRではそのようなメソッドを静的に別の型にすることはできますか?または、既知の非ヌルエンティティに対してcall命令を発行することを許可しますか?

これはDynamicMethodで生成されたコードの唯一の問題ですか?

編集: 私は本当に気にしないので、パフォーマンスの観点からは求めていません。以下のコードは、不安定化アクションを実行するデリゲートを作成し、ランタイムを不安定にすることはありません。これが問題の全体です。なぜ1つは合法で、もう1つは違法ですか?

var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("SomeAssembly"), AssemblyBuilderAccess.Run) ; 
var moduleBuilder = assemblyBuilder.DefineDynamicModule("SomeModule"); 
var typeBuilder = moduleBuilder.DefineType("SomeType"); 
var methodBuilder = typeBuilder.DefineMethod("SomeStaticMethod",MethodAttributes.Public | MethodAttributes.Static,typeof(string),new[]{typeof(object)}); 
var ilgen = methodBuilder.GetILGenerator(); 
ilgen.Emit(OpCodes.Ldarg_0); 
ilgen.Emit(OpCodes.Call, typeof(object).GetMethod("ToString")); 
ilgen.Emit(OpCodes.Ret); 
var newType = typeBuilder.CreateType(); 
var @delegate = Delegate.CreateDelegate(typeof(Func<object, string>),newType.GetMethod("SomeStaticMethod")) as Func<object,string>; 
@delegate(new object()); 

答えて

1

何か間違ったことをしないようにしています。オブジェクトの具体的な型を知ることができないので、ここでの呼び出しは間違っています。オブジェクトが安全であることを知っているので、オブジェクトが表示されているもの以外のものではないことを合法的に知っているコンパイラ(例えば、密閉されたクラスを見るか、オブジェクトをインスタンス化したもの)は、この変換が安全でないように、引数として渡される "オブジェクト"です。 "new object()。ToString()"の場合、オブジェクトの型は完全にオブジェクトであることがわかっているので、仮想呼び出しは必要ありませんが、オブジェクトは引数として渡されますその具体的なタイプが何であるかを知る方法は全くありません。あなたはあまりにもあまりにも心配しないでください。 JITerは、このコードをJITにするときよりもさらによく知っている可能性がありますが、コールバートを直接コールにすることもできますが、逆にそれを実行してコールを間接呼び出しにすることもできます少し心配する。

+0

これは当てはまりますが、なぜ型生成ツールでReflection Emitを使用して生成するコードで許可されているのですか?実際にはオブジェクトのオーバーロードを呼び出すわけではありませんが、実際には直接呼び出しを行います。 –

+0

私が言うことができるのは、Reflection.Emitは、あなたが何をしているのかをあなたが知っていると仮定しているということです。ここでの直接呼び出しがどのように深刻な方法でランタイムを不安定にすることができるかわかりませんが、DynamicMethodがあなたを保護しようとしている最初のインスタンスではそうです。確かめるのは難しいです。 – Stewart

関連する問題