Mono.Cecil
의 경우 MethodDefinition
의 Body
을 의 Body
으로 설정하면 매우 간단 해 보입니다. 간단한 방법의 경우에는 정상적으로 작동합니다. 그러나 사용자 정의 유형 (예 : 새 객체 초기화)이 사용되는 반면 일부 메소드의 경우 작동하지 않습니다 (어셈블리를 다시 쓰는 동안 예외가 발생 함).Mono.Cecil을 사용하여 메서드의 본문을 다른 메서드의 본문으로 바꿉니 까?
//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");
, 난 그냥 그것을 자신을 시도하고 (예 : 제가 위에서 게시 된이 방법 Test
만) 간단한 경우 작동 발견 : 여기
public class Form1 {
public string Test(){
var u = new Uri("SomeUri");
return u.AbsolutePath;
}
}
는 그런 다음 어셈블리를 다시 작성시 실패합니다. 던져진 예외는 다음과 같은 메시지
ArgumentException
입니다 :
"다른 모듈에 선언 된 회원 '선택 System.Uri'수입해야"사실
내가 비슷한 메시지 전에가 발생했습니다 하지만 (string.Concat
)와 같은 메소드 호출 용입니다. 그래서 내가 MethodReference
을 가져 오려고 시도한 것입니다 (게시 한 코드의 foreach
루프 내에서 if
을 볼 수 있습니다). 그리고 그 사실은이 경우에 효과가있었습니다. 하지만이 경우는 다릅니다. 사용 된/참조 된 형식 (이 경우에는 System.Uri
)을 올바르게 가져 오는 방법을 알지 못합니다. Import
의 결과를 사용해야한다는 것을 알고 있으므로 MethodReference
의 경우 각 Instruction
에 대해 Operand
을 바꾸는 데 결과가 사용됨을 알 수 있습니다. 하지만이 경우 유형 참조에 대해서는 전혀 모릅니다.
여기이 경험이있는 사람이 Mono.Cecil
으로이 문제를 해결할 수 있기를 바랍니다. 나는 그것이 단순해야한다고 생각하지만 모노를 이해하지 못할 수도 있습니다. 잘 지켜라. 도와 줘서 고마워.
이 새로운 방법에 대한 호출로 몸을 대체하기 위해 훨씬 더 간단하지 않을까요 : 여기 는
VariableDefinition
를 가져올 단지 유사한 코드? –@JeroenMostert 소스'Test' 메소드는 단지 간단한 코드 일뿐입니다. 실제로 복잡한 코드 (수십 줄이 포함 된 ...)가 될 수 있습니다. 따라서 매번 이러한 코드를 매번 'Instructions'로 변환하면 어렵고 전혀 흥미롭지 않습니다. 기존의 방법을 사용하여 다른 어셈블리에 정의 된 다른 코드를 대체하고 싶습니다.나는 이것이 모노와 함께 할 수 있다고 생각한다. 세실. – Hopeless
아니요, 요점은 - 원하는 메서드 본문이 이미 올바르게 컴파일 된 것입니다 (형식 및 어셈블리 참조와 전체 후프 포함). 새로운 몸체로 이식하려고하는 대신,'Source.Test' 메서드 본문을'Target.Test'에 대한 호출로 대체하지 않을까요? (별도 어셈블리의 존재가 문제가 있다면 먼저 ILMerge하십시오.) 이것은 소스 또는 타겟이 얼마나 복잡한 지 상관없이 작동합니다. –