本文整理汇总了C#中Mono.Cecil.MethodDefinition.EmitMethodCallback方法的典型用法代码示例。如果您正苦于以下问题:C# MethodDefinition.EmitMethodCallback方法的具体用法?C# MethodDefinition.EmitMethodCallback怎么用?C# MethodDefinition.EmitMethodCallback使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类Mono.Cecil.MethodDefinition
的用法示例。
在下文中一共展示了MethodDefinition.EmitMethodCallback方法的2个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C#代码示例。
示例1: InvalidOperationException
/// <summary>
/// Wraps the current method with begin/end callbacks.
/// </summary>
/// <remarks>
/// This will rename the current method and replace it with a new method that will take its place.
/// In the new method it will call the callbacks and perform canceling on the begin callback if required.</remarks>
/// <param name="current">The current method to be wrapped</param>
/// <param name="beginCallback">The callback to be executed at the start of the method</param>
/// <param name="endCallback">The optional end callback that will be executed at the end of the method</param>
/// <param name="beginIsCancellable">Indicates that the begin callback can cancel the method execution</param>
/// <param name="noEndHandling">Indicates to only return from the method and not do any special popping and so on</param>
/// <param name="allowCallbackInstance">Indicates that the callbacks expect an instance parameter at the first parameter index</param>
/// <returns></returns>
public static MethodDefinition Wrap
(
this MethodDefinition current,
MethodReference beginCallback,
MethodReference endCallback,
bool beginIsCancellable,
bool noEndHandling,
bool allowCallbackInstance,
TypeReference overrideReturnType = null
)
{
if (!current.HasBody)
throw new InvalidOperationException("Method must have a body.");
//This method has only yet been tested on void & string return type methods.
if (new[]
{
current.Module.TypeSystem.Void,
current.Module.TypeSystem.String,
current.Module.TypeSystem.Double,
}.Contains(current.ReturnType) || (overrideReturnType != null && current.ReturnType.Name == overrideReturnType.Name))
{
//Create the new replacement method that will take place of the current method.
//So we must ensure we clone to meet the signatures.
var wrapped = new MethodDefinition(current.Name, current.Attributes, current.ReturnType);
var instanceMethod = (current.Attributes & MethodAttributes.Static) == 0;
//Rename the existing method, and replace all references to it so that the new
//method receives the calls instead.
current.Name = current.Name + WrappedMethodNameSuffix;
//If we are renaming a virtual method, it does not need to be virtual anymore
//as we want exclusive control over it.
current.IsVirtual = false;
//Finally replace all instances of the current method with the wrapped method
//that is about to be generated
current.ReplaceWith(wrapped);
//Clone the parameters for the new method
if (current.HasParameters)
{
foreach (var prm in current.Parameters)
{
wrapped.Parameters.Add(prm);
}
}
//Place the new method in the declaring type of the method we are cloning
current.DeclaringType.Methods.Add(wrapped);
//Generate the il that will call and handle the begin callback.
var beginResult = wrapped.EmitBeginCallback(beginCallback, instanceMethod, allowCallbackInstance, beginIsCancellable);
//Emit the il that will execute the actual method that was renamed earlier
var insFirstForMethod = wrapped.EmitMethodCallback(current, instanceMethod, current.ReturnType.Name != current.Module.TypeSystem.String.Name);
//If the begin callback is cancelable, the EmitBeginCallback method will have left a Nop
//instruction so we can direct where to continue on to, rather than exiting the method.
if (beginIsCancellable && beginResult != null && beginResult.OpCode == OpCodes.Nop)
{
if (current.ReturnType.Name == current.Module.TypeSystem.Void.Name)
{
beginResult.OpCode = OpCodes.Brtrue_S;
beginResult.Operand = insFirstForMethod;
}
else if (current.ReturnType.Name == current.Module.TypeSystem.String.Name)
{
beginResult.OpCode = OpCodes.Brtrue;
beginResult.Operand = insFirstForMethod;
}
else if (current.ReturnType.Name == current.Module.TypeSystem.Double.Name)
{
beginResult.OpCode = OpCodes.Brtrue;
beginResult.Operand = insFirstForMethod;
}
else if (overrideReturnType != null && current.ReturnType.Name == overrideReturnType.Name)
{
beginResult.OpCode = OpCodes.Brtrue;
beginResult.Operand = insFirstForMethod;
}
}
//If a end callback is specified then we can also emit the callback to it as well
if (endCallback != null)
{
wrapped.EmitEndCallback(endCallback, instanceMethod, allowCallbackInstance);
}
//.........这里部分代码省略.........
示例2: Run
public override void Run()
{
foreach (var newItem in SourceDefinition.Type("Terraria.Item").Methods.Where(
x => x.Name == "NewItem"
))
{
//In this patch we create a custom DropLoot method that will be the receiver
//of all Item.NewItem calls in NPCLoot.
var typeNpc = this.Type<Terraria.NPC>();
//Create the new DropLoot call in the Terraria.NPC class
var dropLoot = new MethodDefinition("DropLoot", MethodAttributes.Public | MethodAttributes.Static, newItem.ReturnType);
typeNpc.Methods.Add(dropLoot);
dropLoot.Body.InitLocals = true;
var il = dropLoot.Body.GetILProcessor();
//Clone the parameters from the Item.NewItem method (with no byreference)
foreach (var prm in newItem.Parameters)
dropLoot.Parameters.Add(prm);
dropLoot.Parameters.Add(new ParameterDefinition(typeNpc)
{
Name = "npc",
IsOptional = true,
HasDefault = true,
Constant = null
});
//Collect the hooks
var cbkBegin = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.Npc").Method(
"DropLootBegin",
parameters: dropLoot.Parameters,
skipMethodParameters: 1,
substituteByRefs: true
);
var cbkEnd = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.Npc").Method(
"DropLootEnd",
parameters: dropLoot.Parameters,
skipMethodParameters: 0,
substituteByRefs: true
);
//Create the value to hold the new item id
var vrbItemId = new VariableDefinition("otaItem", (cbkBegin.Parameters[0].ParameterType as ByReferenceType).ElementType);
dropLoot.Body.Variables.Add(vrbItemId);
il.Emit(OpCodes.Ldloca_S, vrbItemId); //Loads our variable by reference so our callback and alter it.
var beginResult = dropLoot.EmitBeginCallback(cbkBegin, false, false, false, parameterOffset: 1);
//Inject the begin call
var insFirstForMethod = dropLoot.EmitMethodCallback(newItem, false, false);
//Store the result into our new variable
il.Emit(OpCodes.Stloc, vrbItemId);
//Set the vanilla instruction to be resumed upon continuation of the begin hook.
if (beginResult != null && beginResult.OpCode == OpCodes.Pop)
{
beginResult.OpCode = OpCodes.Brtrue_S;
beginResult.Operand = insFirstForMethod;
//Emit the cancellation return IL
il.InsertAfter(beginResult, il.Create(OpCodes.Ret));
il.InsertAfter(beginResult, il.Create(OpCodes.Ldloc, vrbItemId));
}
//Inject the end callback
dropLoot.EmitEndCallback(cbkEnd, false, false);
//Emit the return value using the result variable we injected
il.Emit(OpCodes.Ldloc, vrbItemId);
il.Emit(OpCodes.Ret);
}
}