Mono.Cecil
の場合、MethodDefinition
のBody
をソースMethodDefinition
のBody
に設定するだけでも簡単です。簡単な方法については、うまくいきます。しかし、いくつかのメソッドでは、(新しいオブジェクトを初期化するために)カスタムタイプを使用するのに対し、(アセンブリを書き戻すときに例外がスローされて)動作しません。ここでMono.Cecilを使用してメソッドのBodyを別のメソッドのBodyに置き換えますか?
私のコードです:上記のコードはどこから参照されていなかった
//in current app
public class Form1 {
public string Test(){
return "Modified Test";
}
}
//in another assembly
public class Target {
public string Test(){
return "Test";
}
}
//the copying code, this works for the above pair of methods
//the context here is of course in the current app
var targetAsm = AssemblyDefinition.ReadAssembly("target_path");
var mr1 = targetAsm.MainModule.Import(typeof(Form1).GetMethod("Test"));
var targetType = targetAsm.MainModule.Types.FirstOrDefault(e => e.Name == "Target");
var m2 = targetType.Methods.FirstOrDefault(e => e.Name == "Test");
var m1 = mr1.Resolve();
var m1IL = m1.Body.GetILProcessor();
foreach(var i in m1.Body.Instructions.ToList()){
var ci = i;
if(i.Operand is MethodReference){
var mref = i.Operand as MethodReference;
ci = m1IL.Create(i.OpCode, targetType.Module.Import(mref));
}
else if(i.Operand is TypeReference){
var tref = i.Operand as TypeReference;
ci = m1IL.Create(i.OpCode, targetType.Module.Import(tref));
}
if(ci != i){
m1IL.Replace(i, ci);
}
}
//here the source Body should have its Instructions set imported fine
//so we just need to set its Body to the target's Body
m2.Body = m1.Body;
//finally write to another output assembly
targetAsm.Write("modified_target_path");
、私はちょうどそれを自分自身を試してみましたが、それは(私は上記の投稿、そのような2つの方法Test
用など)の単純な例の作品を発見。
public class Form1 {
public string Test(){
var u = new Uri("SomeUri");
return u.AbsolutePath;
}
}
そして、それが戻ってアセンブリを書く時に失敗します。しかし、場合(現在のアプリケーションで定義された)ソースメソッドは次のように、(例えば、いくつかのコンストラクタのinitなど...)いくつかのタイプの参照が含まれています。スローされた例外は、次のようなメッセージでArgumentException
です:
「メンバー 『のSystem.Uri』別のモジュールで宣言され、インポートする必要がある」実際に
私は前に同様のメッセージを遭遇しましたそれは(string.Concat
)のようなメソッド呼び出しのためです。それで、私がMethodReference
をインポートしようとしたのです(私が投稿したコードのforeach
ループ内にif
があります)。そして、本当にそれはその事件のために働いた。しかし、このケースは異なります。使用/参照されるタイプ(この場合はSystem.Uri
)を正しくインポートする方法がわかりません。 Import
の結果を使用する必要があることを知っているので、MethodReference
の場合は、それぞれInstruction
のOperand
を置き換えるために結果が使用されています。しかし、この場合の型参照のために、私は完全にどのように考えていません。
ここで誰かがMono.Cecil
で経験した人がこの問題を解決してくれることを願っています。私はシンプルであるべきだと思っていますが、私はモノを理解していないかもしれません。ご協力ありがとうございました。
は、新しいメソッドを呼び出して、本体を交換するためにはるかに簡単ではないでしょうか? –
@JeroenMostertここで、ソース 'Test'メソッドは単なる単純なものです。実際には複雑なコード(何十行も含む...)である可能性があります。だから毎回これらのコードを手動で 'Instructions'に変換すれば、それは難しく、全く面白くないでしょう。私は別のアセンブリで定義された別のコードを置き換えるために既存のメソッドを使用したいと思います。私は本当にこれがMono.Cecilと似ていると思います。 – Hopeless
いいえ、私の要点は、あなたが望むメソッド本体が既に正しくコンパイルされていることです(型とアセンブリの参照と全体のホップラを含む)。それを新しいボディに移植しようとするのではなく、 'Source.Test'メソッド本体を' Target.Test'の呼び出しで置き換えてみませんか? (別のアセンブリの存在が問題であれば、最初にILMergeします)。これは、ソースまたはターゲットの複雑さに関係なく機能します。 –