I am currently using Calling a method of existing object using IL Emit as a guide, and I can already do whatever is asked in question. Now, I have an attribute added to a parameter and I want to load that particular parameter's attribute so that I can call a method inside that attribute.
I know it can be done by loading the MethodInfo and then getting the ParameterInfo and then getting attribute of that ParameterInfo in IL; I am simply trying to avoid writing that much IL.
Is there a way to load a parameter's attribute in IL just like it is mentioned in the linked post?
Edit:
I have a method with a signature like
Method([Attr] int Parameter)
and I want to load a method which is part of the Attr. I was just hoping I could load ParameterInfo (obtained using MethodInfo.GetParameters()) directly onto the stack. Turns out, LdToken doesn't really allow putting ParameterInfo. Only other way I can think of doing this is to load MethodInfo (LdToken supports that) and then use GetParameters() in IL to get an array of Parameters and then loop through them in IL one by one to get each one's Attribute (using .GetCustomAttribute(Type)) and then call the method on that attribute. Note that I don't have to get a field of an attribute, I need to call a method on that attribute.
K, third time lucky based on another interpretation of the question; here, we're assuming that we want to invoke methods on an attribute instance. We need to consider that attributes only kinda sorta exist at runtime - we can create synthetic instances of the attribute as represented by the metadata, but this isn't particularly cheap or fast, so we should ideally only do this once (the metadata isn't going to change, after all). This means we might want to store the instance as a field somewhere. This could be an instance field, or a static field - in many cases, a static field is fine. Consider:
using System;
using System.Reflection;
using System.Reflection.Emit;
public class SomethingAttribute : Attribute
{
public SomethingAttribute(string name)
=> Name = name;
public string Name { get; }
public void SomeMethod(int i)
{
Console.WriteLine($"SomeMethod: {Name}, {i}");
}
}
public static class P
{
public static void Foo([Something("Abc")] int x)
{
Console.WriteLine($"Foo: {x}");
}
public static void Main()
{
// get the attribute
var method = typeof(P).GetMethod(nameof(Foo));
var p = method.GetParameters()[0];
var attr = (SomethingAttribute)Attribute.GetCustomAttribute(p, typeof(SomethingAttribute));
// define an assembly, module and type to play with
AssemblyBuilder asm = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Evil"), AssemblyBuilderAccess.Run);
var module = asm.DefineDynamicModule("Evil");
var type = module.DefineType("SomeType", TypeAttributes.Public);
// define a field where we'll store our synthesized attribute instance; avoid initonly, unless you're
// going to write code in the .cctor to initialize it; leaving it writable allows us to assign it via
// reflection
var attrField = type.DefineField("s_attr", typeof(SomethingAttribute), FieldAttributes.Static | FieldAttributes.Private);
// declare the method we're working on
var bar = type.DefineMethod("Bar", MethodAttributes.Static | MethodAttributes.Public, typeof(void), new[] { typeof(int) });
var il = bar.GetILGenerator();
// use the static field instance as our target to invoke the attribute method
il.Emit(OpCodes.Ldsfld, attrField); // the attribute instance
il.Emit(OpCodes.Ldarg_0); // the integer
il.EmitCall(OpCodes.Callvirt, typeof(SomethingAttribute).GetMethod(nameof(SomethingAttribute.SomeMethod)), null);
// and also call foo
il.Emit(OpCodes.Ldarg_0); // the integer
il.EmitCall(OpCodes.Call, typeof(P).GetMethod(nameof(P.Foo)), null);
il.Emit(OpCodes.Ret);
// complete the type
var actualType = type.CreateType();
// assign the synthetic attribute instance on the concrete type
actualType.GetField(attrField.Name, BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, attr);
// get a delegate to the method
var func = (Action<int>)Delegate.CreateDelegate(typeof(Action<int>), actualType.GetMethod(bar.Name));
// and test it
for (int i = 0; i < 5; i++)
func(i);
}
}
Output from the final loop (for (int i = 0; i < 5; i++) func(i);):
SomeMethod: Abc, 0
Foo: 0
SomeMethod: Abc, 1
Foo: 1
SomeMethod: Abc, 2
Foo: 2
SomeMethod: Abc, 3
Foo: 3
SomeMethod: Abc, 4
Foo: 4
As a side note; in many ways it is easier to do this with expression-trees, since expression-trees have Expression.Constant which can be the attribute instance, and which is treated like a field internally. But you mentioned TypeBuilder, so I went this way :)
I know it can be done by loading the MethodInfo and then getting the ParameterInfo and then getting attribute of that ParameterInfo in IL; I am simply trying to avoid writing that much IL.
Yeah, that's pretty much it, in IL; IL is powerful, but is not particularly terse or simple. Just like in the linked post, you'd end up loading the parameter (ldarg or ldarga, maybe some .s), then depending on whether the member is a field or a property, using either ldfld or callvirt on the property getter. About 3 lines, so not huge; perhaps something like:
static void EmitLoadPropertyOrField(ILGenerator il, Type type, string name)
{
// assumes that the target *reference* has already been loaded; only
// implements reference-type semantics currently
var member = type.GetMember(name, BindingFlags.Public | BindingFlags.Instance).Single();
switch (member)
{
case FieldInfo field:
il.Emit(OpCodes.Ldfld, field);
break;
case PropertyInfo prop:
il.EmitCall(OpCodes.Callvirt, prop.GetGetMethod(), null);
break;
default:
throw new InvalidOperationException();
}
}
If you're trying to save complexity (or are sick of InvalidProgramException), another viable approach is to use expression trees; then you have many more convenience features, but in particular things like:
var p = Expression.Parameter(typeof(Foo), "x");
var name = Expression.PropertyOrField(p, "Name");
// ...
var lambda = Expression.Lambda<YourDelegateType>(body, p);
var del = lambda.Compile();
Note that expression trees cannot be used in all scenarios; for example, they can't really be used with TypeBuilder; conversely, though, they can do things that IL-emit can't - for example, in AOT scenarios where IL-emit is prohibited, they can work as a runtime reflection evaluated tree, so it still works (but: slower). They add some additional processing (building and then parsing the tree), but: they are simpler than IL-emit, especially for debugging.
With the clarification that by attribute you really did mean a .NET attribute (not a field or property), this becomes simpler in many ways; consider:
class SomethingAttribute : Attribute
{
public SomethingAttribute(string name)
=> Name = name;
public string Name { get; }
}
static class P
{
public static void Foo([Something("Abc")] int x) {}
static void Main()
{
var method = typeof(P).GetMethod(nameof(Foo));
var p = method.GetParameters()[0];
var attr = (SomethingAttribute)Attribute.GetCustomAttribute(
p, typeof(SomethingAttribute));
string name = attr?.Name;
// you can now "ldstr {name}" etc
}
}
The important point here is that the attribute isn't going to change at runtime - it is pure metadata; so, we can load it once with reflection when we are processing the model, then just emit the processed data, i.e. the line
// you can now "ldstr {name}" etc
For future reference, I actually went ahead and loaded ParameterInfo using IL only. Marc's solution was good, but it quickly became infeasible after the number of parameter based attributes increased. We plan to use attributes to contain some state specific information, we would have to use a ton of reflection from outside the type to find and assign correct attribute to the field. Overall, it would have become quite hectic to deal with it.
To load ParameterInfo using IL
IL.Emit(OpCodes.Ldtoken, Method); // Method is MethodInfo as we can't use GetParameters with MethodBuilder
IL.Emit(OpCodes.Call, typeof(MethodBase).GetMethod(nameof(MethodBase.GetMethodFromHandle), new[] { typeof(RuntimeMethodHandle) }));
IL.Emit(OpCodes.Callvirt, typeof(MethodInfo).GetMethod(nameof(MethodInfo.GetParameters)));
var ILparameters = IL.DeclareLocal(typeof(ParameterInfo[]));
IL.Emit(OpCodes.Stloc, ILparameters);
that loads ParameterInfo onto stack and then stores it into a LocalBuilder called ILparameters. Note that it is an array. Items of this array can then be accessed like
IL.Emit(OpCodes.Ldloc, ILparameters);
IL.Emit(OpCodes.Ldc_I4, Number); // Replace with Ldc_I4_x if number < 8
IL.Emit(OpCodes.Ldelem_Ref);
I prefer to create two helper functions for the two code pieces. It works pretty well.
Related
You can pass in a method into another method that's takes Func<>. But can you pass that in as a dynamically named string so you can what method is passed in on the fly?
You can pass in a method into another method that's takes Func<>.
It's worth separating out the "passing a value" from "creating the value in the first place". When you write code such as:
InvokeSomeDelegate(MethodToInvoke);
That's performing a method group conversion to create a delegate instance. In other words, it's equivalent to:
Func<Whatever> func = MethodToInvoke;
InvokeSomeDelegate(func);
So really the question isn't so much about how you can pass a string into the method, as how to create a delegate based on a string. That in turn leads to the question of what kind of method, what type it's in etc.
The framework method you want to use is Delegate.CreateDelegate, but exactly how you use that will depend on the context, so that you can find the right MethodInfo with reflection. Here's an example:
using System;
using System.Reflection;
class Test
{
static void Main()
{
InvokeFunc("Double");
InvokeFunc("Quadruple");
InvokeFunc("AddOne");
}
static void InvokeFunc(string name)
{
// Note that in our case they're all private static methods. You'd
// need to adjust the binding flags if that's not the case. If you
// need to worry about multiple overloads, that makes it harder too.
MethodInfo method = typeof(Test)
.GetMethod(name, BindingFlags.NonPublic | BindingFlags.Static);
// TODO: Validate that you've got a method
var func = (Func<int, int>) Delegate.CreateDelegate(
typeof(Func<int, int>), // Delegate type to create
null, // Target of method call; null because ours are static
method); // Method to create a delegate for
var result = func(10);
Console.WriteLine($"{name}(10) => {result}");
}
static int Double(int x) => x * 2;
static int Quadruple(int x) => x * 4;
static int AddOne(int x) => x + 1;
}
Note that all the reflection to find the method and then create the delegate is relatively slow. If you're doing this with any significant performance constraints, you may want to add caching.
Intro
I am working on some code that relies heavily on reflection. Some parts that are at the core are used repeatedly. Optimizing this in even the slightest way will give me a lot(to various degrees) of performance benefits.
Context
The core consists of getting data out of an object. Currently I use reflection to get a PropertyInfo object, and then use the following code to construct a Func<object,object>:
public static Func<object, object> BuildUntypedGetter(PropertyInfo propertyInfo)
{
var targetType = propertyInfo.DeclaringType;
var methodInfo = propertyInfo.GetGetMethod();
var exTarget = System.Linq.Expressions.Expression.Parameter(typeof(object), "t");
var exBody0 = System.Linq.Expressions.Expression.Convert(exTarget, targetType);
var exBody = System.Linq.Expressions.Expression.Call(exBody0, methodInfo);
var exBody2 = System.Linq.Expressions.Expression.Convert(exBody, typeof(object));
var lambda = System.Linq.Expressions.Expression.Lambda<Func<object, object>>(exBody2, exTarget);
var action = lambda.Compile();
return action;
}
This resulting Func<object,object> is what I then cache and use. The actual typing and security for not calling it on other objects types but the original is something I do not have to worry about as this is taken care of.
In the above code, the lambda that is created looks like the following:
.Lambda #Lambda1<System.Func`2[System.Object,System.Object]>(System.Object $t) {
(System.Object).Call ((MyObjectType)$t).get_Id()
}
where Id is the attribute that this was generated on.
As you can see, this is merely a redirection. All it does is call the getter.
Question
Is there a way to just return the getter (get_Id) as a Func<object,object> without the extra cast and call? OR are there maybe other more efficient ways to call an object.attribute getter with an object type as instance type?
Is there a way to just return the getter (get_Id) as a
Func without the extra cast and call?
C# will not let you call getter without the cast (of course with the exception of dynamic type, but that's another story), because that would violate type safety, that C# guarantees.
But you can emit IL code, that does not contain such cast and calls getter directly. Of course, when you outsmart compiler like this, it is then your responsibility to call this method only on objects of correct type, otherwise your application is likely to crash.
Following code shows how to emit such IL code. My measurements indicates, that in Release mode, emitted delegate is approx. 3x faster than your compiled lambda (in Debug mode, it seems to be actually a bit slower).
public static Func<object, object> EmitUntypedGetter(PropertyInfo pi)
{
DynamicMethod method = new DynamicMethod(
"PropertyGetter",
typeof(Object),
new[] { typeof(Object) },
Assembly.GetExecutingAssembly().ManifestModule);
ILGenerator il = method.GetILGenerator(100);
// Load object onto the stack.
il.Emit(OpCodes.Ldarg_0);
// Call property getter
il.EmitCall(OpCodes.Callvirt, pi.GetGetMethod(), null);
// If property returns value-type, value must be boxed
if(pi.PropertyType.IsValueType)
il.Emit(OpCodes.Box, pi.PropertyType);
// Exit method
il.Emit(OpCodes.Ret);
return (Func<Object, Object>)method.CreateDelegate(typeof(Func<Object, Object>));
}
EDIT:
On my computer, performance of emitted code is consistently much faster that lambda version.
Tested on Windows 10 Home, CPU Intel Core2 Q9400, compiled with Visual Studio 2017 CE v. 15.4.0, Console App targeting .NET Framework 4.7, Release mode (Optimize code option in project properties enabled), executed outside of Visual Studio (with VS attached, some optimizations are disabled)
My results:
Compiled lambda (value type) : 40827 ms
Compiled lambda (reference type) : 37558 ms
Emit (value type) : 16963 ms
Emit (reference type) : 11903 ms
Program used for testing:
public struct MyClass
{
public int I => 42;
public string S => "foo";
}
public static void Main()
{
var valueTypeProperty = typeof(MyClass).GetProperty("I");
var referenceTypeProperty = typeof(MyClass).GetProperty("S");
var lambdaValueTypeGetterDelegate = BuildUntypedGetter(valueTypeProperty);
var lambdaReferenceTypeGetterDelegate = BuildUntypedGetter(referenceTypeProperty);
var emitValueTypeGetterDelegate = EmitUntypedGetter(valueTypeProperty);
var emitReferenceTypeGetterDelegate = EmitUntypedGetter(referenceTypeProperty);
//warm-up - ensures that delegates are properly jitted
lambdaValueTypeGetterDelegate(new MyClass());
lambdaReferenceTypeGetterDelegate(new MyClass());
emitValueTypeGetterDelegate(new MyClass());
emitReferenceTypeGetterDelegate(new MyClass());
TestDelegate("Compiled lambda (value type) ", lambdaValueTypeGetterDelegate);
TestDelegate("Compiled lambda (reference type) ", lambdaReferenceTypeGetterDelegate);
TestDelegate("Emit (value type) ", emitValueTypeGetterDelegate);
TestDelegate("Emit (reference type) ", emitReferenceTypeGetterDelegate);
Console.ReadLine();
}
private static void TestDelegate(string description, Func<object, object> getterDelegate)
{
const long LOOPS_COUNT = 1_000_000_000;
var obj = new MyClass();
Stopwatch sw = new Stopwatch();
sw.Start();
for (long i = 0; i < LOOPS_COUNT; i++)
{
getterDelegate(obj);
}
sw.Stop();
Console.WriteLine($"{description}: {sw.ElapsedMilliseconds} ms");
}
Is there a way to just return the getter (get_Id) as a Func without the extra cast and call?
Not in a way that satisfies your requirements. While it is generally possible to dynamically bind a delegate directly to a method (or property accessor), the delegate type must be signature-compatible with the method you are binding to. That's not the case for you.
Consider this example:
class MyClass {
string Id { get; set; }
}
Here, your accessor expressed in terms of Func<,> would be Func<MyClass, String>. You, however, want a Func<object, object>. You're changing both the argument type and the return type. That is only permissible within certain constraints.
The type Func<-T, +TReturn> is contravariant on its input type T and covariant on its output type TReturn. Thus, a Func<,> instance is convertible to another instantiation when the target type is more specific for T or less specific for TReturn. For example:
Func<object, *> is convertible to Func<string, *> because a function that takes in an object can always take in a string. The reverse is not true.
Func<*, string> is convertible to Func<*, object> because a function that returns a string always returns an object. Again, the reverse is not true.
In C#, these rules are strictly enforced. A generic parameter can be covariant when it only appears as an output; or contravariant when it only appears as an input. Furthermore, this variance is only applicable to reference types, meaning Func<*, int> is not assignable to Func<*, object>.
I'm afraid there's no way around it: any method you bind to a Func<object, object> must accept an object argument, which means you need an intermediate method that casts down to your source type. It also needs to explicitly box primitive return values. While you could eliminate some of the conversions by emitting the IL directly, as #Ňuf has shown, I don't think you'll see a meaningful impact.
However, depending on how you're using the values you pull out, there may be a better way. Instead of using generated code to pull values into the C# universe where you can operate on them, it may be feasible to do the opposite: push that logic down into generated code, which you could specialize according to the types you're working with. Or, alternatively, make that logic generic, and use the runtime code generation to dispatch to the correct generic instantiation.
I'm not sure of the terminology for this kind of code, but I want to know if it's possible to instantiate variables after the parentheses, but whilst using reflection.
I have a map which gets loaded from an XML file. This is a collection of (int X, int Y, string S) where the X,Y is the position of some terrain, and S is a string representing the type of the terrain. I have a dictionary to pass between the strings and the relevant types; for example one key-value pair might be "Tree", typeof(Tree).
When using reflection, although I know it's possible to instantiate with parameters, the only way I'm comfortable is just by using Activator.CreateInstance(Type t), i.e. with an empty constructor.
When I had the maps hard coded, I would originally instantiate like this (within some i,j for loop):
case: "Tree"
world.Add( new Tree(i,j) );
Whilst starting to think about reflection and my save file, I changed this to:
world.Add( new Tree() { X = i, Y = j }
However, I realised that this won't work with reflection, so I am having to do the following (Tree inherits from Terrain, and the dictionary just converts the XML save data string to a type):
Type type = dictionary[dataItem.typeAsString];
Terrain t = (Terrain)Activator.CreateInstance(type);
t.X = i;
t.Y = j;
world.Add(t);
I would prefer to do this using something like
Type type = dictionary[dataItem.typeAsString];
world.Add((Terrain)Activator.CreateInstance(type) { X = i, Y = j }
Is there any shortcut like this? I guess if not I could edit world.Add to take an X and Y and cast to Terrain in there to access those variables, but I am still curious as to a) what this {var1 = X, var2 = Y} programming is called, and b) whether something similar exists when using reflection.
This syntax is called Object Initializer syntax and is just syntactic sugar for setting the properties.
The code var result = new MyType { X = x } will be compiled to this:
MyType __tmp = new MyType();
__tmp.X = x;
MyType result = __tmp;
You will have to do that yourself using PropertyInfo.SetValue if you know the instantiated type only at runtime or use the normal property setters if the type is known at compile time.
The answer is no, because the object initialization syntax you mention (introduced with LINQ in 3.0) is an illusion of the compiler. As in, when you type this
var foo = new Foo { Bar = "baz" };
the compiler actually converts it into CLS-compliant IL which equates to
var foo = new Foo();
foo.Bar = "baz";
Phil Haack has a great blog post which not only covers the details of this rewriting done by the compiler, but also some side effects it can cause when dealing with types that implement IDisposable
As all of this is nothing but a feint by the compiler, there is no equivalent using reflection (i.e., Activator.CreateInstance(Type t)). Others will give you workarounds, but in the end there really is no direct equivalent.
Probably the closest generic hack you could manage would be to create a method that accepted an object, then used reflection in order to identify the properties of that object and their respective values in order to perform object initialization for you. It might be used something like this
var foo = Supercollider.Initialize<Foo>(new { Bar = "baz" });
and the code would be something like (this is off the top of my head)
public sealed class Supercollider
{
public static T Initialize<T>(object propertySource)
{
// you can provide overloads for types that don't have a default ctor
var result = Activator.CreateInstance(typeof(T));
foreach(var prop in ReflectionHelper.GetProperties(typeof(T)))
ReflectionHelper.SetPropertyValue(
result, // the target
prop, // the PropertyInfo
propertySource); // where we get the value
}
}
You'd have to get each property from the anonymous object, find a property in your target type with the same exact name and type, then get the value from that property in the anonymous object and set the value of your target's property to this value. Its not incredibly hard, but its absolutely prone to runtime exceptions and issues where the compiler chooses a different type for the anonymous type's property, requiring you be more specific (e.g., new { Bar = (string)null }), which screws with the elegance of the thing.
(T)Activator.CreateInstance(typeof(T), param1, param2, ...);
As described HERE.
public sealed class ReflectionUtils
{
public static T ObjectInitializer<T>(Action<T> initialize)
{
var result = Activator.CreateInstance<T>();
initialize(result);
return result;
}
}
public class MyModel
{
public string Name{get;set;}
}
And after that just make the call :
var myModel = ReflectionUtils.ObjectInitializer<MyModel>(m =>
{
m.Name = "Asdf"
});
The advantage is that in this way you will have type safety and use reflection as minimum required, because we all know that reflection is an expensive operation that should be avoided as much as possible.
You could create a constructor which takes those arguments, then use
Activator.CreateInstance(type, i, j)
But you won't be able to use the object initialization syntax. Which is just sugar candy for setting the properties.
(First of all, this is a very lengthy post, but don't worry: I've already implemented all of it, I'm just asking your opinion, or possible alternatives.)
I'm having trouble implementing the following; I'd appreciate some help:
I get a Type as parameter.
I define a subclass using reflection. Notice that I don't intend to modify the original type, but create a new one.
I create a property per field of the original class, like so:
public class OriginalClass {
private int x;
}
public class Subclass : OriginalClass {
private int x;
public int X {
get { return x; }
set { x = value; }
}
}
For every method of the superclass, I create an analogous method in the subclass. The method's body must be the same except that I replace the instructions ldfld x with callvirt this.get_X, that is, instead of reading from the field directly I call the get accessor.
I'm having trouble with step 4. I know you're not supposed to manipulate code like this, but I really need to.
Here's what I've tried:
Attempt #1: Use Mono.Cecil. This would allow me to parse the body of the method into human-readable Instructions, and easily replace instructions. However, the original type isn't in a .dll file, so I can't find a way to load it with Mono.Cecil. Writing the type to a .dll, then load it, then modify it and write the new type to disk (which I think is the way you create a type with Mono.Cecil), and then load it seems like a huge overhead.
Attempt #2: Use Mono.Reflection. This would also allow me to parse the body into Instructions, but then I have no support for replacing instructions. I've implemented a very ugly and inefficient solution using Mono.Reflection, but it doesn't yet support methods that contain try-catch statements (although I guess I can implement this) and I'm concerned that there may be other scenarios in which it won't work, since I'm using the ILGenerator in a somewhat unusual way. Also, it's very ugly ;). Here's what I've done:
private void TransformMethod(MethodInfo methodInfo) {
// Create a method with the same signature.
ParameterInfo[] paramList = methodInfo.GetParameters();
Type[] args = new Type[paramList.Length];
for (int i = 0; i < args.Length; i++) {
args[i] = paramList[i].ParameterType;
}
MethodBuilder methodBuilder = typeBuilder.DefineMethod(
methodInfo.Name, methodInfo.Attributes, methodInfo.ReturnType, args);
ILGenerator ilGen = methodBuilder.GetILGenerator();
// Declare the same local variables as in the original method.
IList<LocalVariableInfo> locals = methodInfo.GetMethodBody().LocalVariables;
foreach (LocalVariableInfo local in locals) {
ilGen.DeclareLocal(local.LocalType);
}
// Get readable instructions.
IList<Instruction> instructions = methodInfo.GetInstructions();
// I first need to define labels for every instruction in case I
// later find a jump to that instruction. Once the instruction has
// been emitted I cannot label it, so I'll need to do it in advance.
// Since I'm doing a first pass on the method's body anyway, I could
// instead just create labels where they are truly needed, but for
// now I'm using this quick fix.
Dictionary<int, Label> labels = new Dictionary<int, Label>();
foreach (Instruction instr in instructions) {
labels[instr.Offset] = ilGen.DefineLabel();
}
foreach (Instruction instr in instructions) {
// Mark this instruction with a label, in case there's a branch
// instruction that jumps here.
ilGen.MarkLabel(labels[instr.Offset]);
// If this is the instruction that I want to replace (ldfld x)...
if (instr.OpCode == OpCodes.Ldfld) {
// ...get the get accessor for the accessed field (get_X())
// (I have the accessors in a dictionary; this isn't relevant),
MethodInfo safeReadAccessor = dataMembersSafeAccessors[((FieldInfo) instr.Operand).Name][0];
// ...instead of emitting the original instruction (ldfld x),
// emit a call to the get accessor,
ilGen.Emit(OpCodes.Callvirt, safeReadAccessor);
// Else (it's any other instruction), reemit the instruction, unaltered.
} else {
Reemit(instr, ilGen, labels);
}
}
}
And here comes the horrible, horrible Reemit method:
private void Reemit(Instruction instr, ILGenerator ilGen, Dictionary<int, Label> labels) {
// If the instruction doesn't have an operand, emit the opcode and return.
if (instr.Operand == null) {
ilGen.Emit(instr.OpCode);
return;
}
// Else (it has an operand)...
// If it's a branch instruction, retrieve the corresponding label (to
// which we want to jump), emit the instruction and return.
if (instr.OpCode.FlowControl == FlowControl.Branch) {
ilGen.Emit(instr.OpCode, labels[Int32.Parse(instr.Operand.ToString())]);
return;
}
// Otherwise, simply emit the instruction. I need to use the right
// Emit call, so I need to cast the operand to its type.
Type operandType = instr.Operand.GetType();
if (typeof(byte).IsAssignableFrom(operandType))
ilGen.Emit(instr.OpCode, (byte) instr.Operand);
else if (typeof(double).IsAssignableFrom(operandType))
ilGen.Emit(instr.OpCode, (double) instr.Operand);
else if (typeof(float).IsAssignableFrom(operandType))
ilGen.Emit(instr.OpCode, (float) instr.Operand);
else if (typeof(int).IsAssignableFrom(operandType))
ilGen.Emit(instr.OpCode, (int) instr.Operand);
... // you get the idea. This is a pretty long method, all like this.
}
Branch instructions are a special case because instr.Operand is SByte, but Emit expects an operand of type Label. Hence the need for the Dictionary labels.
As you can see, this is pretty horrible. What's more, it doesn't work in all cases, for instance with methods that contain try-catch statements, since I haven't emitted them using methods BeginExceptionBlock, BeginCatchBlock, etc, of ILGenerator. This is getting complicated. I guess I can do it: MethodBody has a list of ExceptionHandlingClause that should contain the necessary information to do this. But I don't like this solution anyway, so I'll save this as a last-resort solution.
Attempt #3: Go bare-back and just copy the byte array returned by MethodBody.GetILAsByteArray(), since I only want to replace a single instruction for another single instruction of the same size that produces the exact same result: it loads the same type of object on the stack, etc. So there won't be any labels shifting and everything should work exactly the same. I've done this, replacing specific bytes of the array and then calling MethodBuilder.CreateMethodBody(byte[], int), but I still get the same error with exceptions, and I still need to declare the local variables or I'll get an error... even when I simply copy the method's body and don't change anything.
So this is more efficient but I still have to take care of the exceptions, etc.
Sigh.
Here's the implementation of attempt #3, in case anyone is interested:
private void TransformMethod(MethodInfo methodInfo, Dictionary<string, MethodInfo[]> dataMembersSafeAccessors, ModuleBuilder moduleBuilder) {
ParameterInfo[] paramList = methodInfo.GetParameters();
Type[] args = new Type[paramList.Length];
for (int i = 0; i < args.Length; i++) {
args[i] = paramList[i].ParameterType;
}
MethodBuilder methodBuilder = typeBuilder.DefineMethod(
methodInfo.Name, methodInfo.Attributes, methodInfo.ReturnType, args);
ILGenerator ilGen = methodBuilder.GetILGenerator();
IList<LocalVariableInfo> locals = methodInfo.GetMethodBody().LocalVariables;
foreach (LocalVariableInfo local in locals) {
ilGen.DeclareLocal(local.LocalType);
}
byte[] rawInstructions = methodInfo.GetMethodBody().GetILAsByteArray();
IList<Instruction> instructions = methodInfo.GetInstructions();
int k = 0;
foreach (Instruction instr in instructions) {
if (instr.OpCode == OpCodes.Ldfld) {
MethodInfo safeReadAccessor = dataMembersSafeAccessors[((FieldInfo) instr.Operand).Name][0];
// Copy the opcode: Callvirt.
byte[] bytes = toByteArray(OpCodes.Callvirt.Value);
for (int m = 0; m < OpCodes.Callvirt.Size; m++) {
rawInstructions[k++] = bytes[put.Length - 1 - m];
}
// Copy the operand: the accessor's metadata token.
bytes = toByteArray(moduleBuilder.GetMethodToken(safeReadAccessor).Token);
for (int m = instr.Size - OpCodes.Ldfld.Size - 1; m >= 0; m--) {
rawInstructions[k++] = bytes[m];
}
// Skip this instruction (do not replace it).
} else {
k += instr.Size;
}
}
methodBuilder.CreateMethodBody(rawInstructions, rawInstructions.Length);
}
private static byte[] toByteArray(int intValue) {
byte[] intBytes = BitConverter.GetBytes(intValue);
if (BitConverter.IsLittleEndian)
Array.Reverse(intBytes);
return intBytes;
}
private static byte[] toByteArray(short shortValue) {
byte[] intBytes = BitConverter.GetBytes(shortValue);
if (BitConverter.IsLittleEndian)
Array.Reverse(intBytes);
return intBytes;
}
(I know it isn't pretty. Sorry. I put it quickly together to see if it would work.)
I don't have much hope, but can anyone suggest anything better than this?
Sorry about the extremely lengthy post, and thanks.
UPDATE #1: Aggh... I've just read this in the msdn documentation:
[The CreateMethodBody method] is
currently not fully supported. The
user cannot supply the location of
token fix ups and exception handlers.
I should really read the documentation before trying anything. Some day I'll learn...
This means option #3 can't support try-catch statements, which makes it useless for me. Do I really have to use the horrible #2? :/ Help! :P
UPDATE #2: I've successfully implemented attempt #2 with support for exceptions. It's quite ugly, but it works. I'll post it here when I refine the code a bit. It's not a priority, so it may be a couple of weeks from now. Just letting you know in case someone is interested in this.
Thanks for your suggestions.
I am trying to do a very similar thing. I have already tried your #1 approach, and I agree, that creates a huge overhead (I haven't measured it exactly though).
There is a DynamicMethod class which is - according to MSDN - "Defines and represents a dynamic method that can be compiled, executed, and discarded. Discarded methods are available for garbage collection."
Performance wise it sounds good.
With the ILReader library I could convert normal MethodInfo to DynamicMethod. When you look into the ConvertFrom method of the DyanmicMethodHelper class of the ILReader library you can find the code we'd need:
byte[] code = body.GetILAsByteArray();
ILReader reader = new ILReader(method);
ILInfoGetTokenVisitor visitor = new ILInfoGetTokenVisitor(ilInfo, code);
reader.Accept(visitor);
ilInfo.SetCode(code, body.MaxStackSize);
Theoretically this let's us modify the code of an existing method and run it as a dynamic method.
My only problem now is that Mono.Cecil does not allow us to save the bytecode of a method (at least I could not find the way to do it). When you download the Mono.Cecil source code it has a CodeWriter class to accomplish the task, but it is not public.
Other problem I have with this approach is that MethodInfo -> DynamicMethod transformation works only with static methods with ILReader. But this can be worked around.
The performance of the invocation depends on the method I used. I got following results after calling short method 10'000'000 times:
Reflection.Invoke - 14 sec
DynamicMethod.Invoke - 26 sec
DynamicMethod with delegates - 9 sec
Next thing I'm going to try is:
load original method with Cecil
modify the code in Cecil
strip off of the unmodified code from the assembly
save the assembly as MemoryStream instead of File
load the new assembly (from memory) with Reflection
call the method with reflection invoke if its a one-time call
generate DynamicMethod's delegates and store them if I want to call that method regularly
try to find out if I can unload the not necessary assemblies from memory (free up both MemoryStream and run-time assembly representation)
It sounds like a lot of work and it might not work, we'll see :)
I hope it helps, let me know what you think.
Have you tried PostSharp? I think that it already provides all you'd need out of the box via the On Field Access Aspect.
Maybe i unterstood something wrong, but if you like to extend, intercept an existing instance of a class you can take a look into Castle Dynamic Proxy.
You'd have to define the properties in the base class as virtual or abstract first.
Also,the fields then need to be modified to be 'protected' as opposed to 'private'.
Or am I misunderstanding something here?
What about using SetMethodBody instead of CreateMethodBody (this would be a variation of #3)? It's a new method introduced in .NET 4.5 and seems to support exceptions and fixups.
Basically you are copying the program text of the original class, and then making regular changes to it. Your current method is to copy the object code for the class and patch that. I can understand why that seems ugly; you're working at an extremely low level.
This seems like it would be easy to do with source-to-source program transformations.
This operates on the AST for the source code rather than the source code itself for precisions. See DMS Software Reengineering Toolkit for such a tool. DMS has a full C# 4.0 parser.
I'm having trouble emitting a call to a delegate whose type is unfinished at the time of the emit. I'll elaborate: I've declared the following delegate type:
// Delegate type. The 'firstArgument' will be 'this', i.e., this is an open
// instance method: the implicit argument is here given explicitly, in
// 'firstArgument'. (See link below for explanation on open instance delegates).
public delegate Object DirectReadAccessor<T>(T firstArgument);
And now I'm trying to dynamically (i.e., with a TypeBuilder) create the following class:
public MyClass {
// Array of delegates. T has been replaced with MyClass because the
// argument will be 'this', which is of type MyClass.
private static DirectReadAccessor<MyClass>[] directReadAccessors;
// Method that looks up a delegate in the array of delegates and calls it
// with 'this'.
public Object DirectRead(int i) {
directReadAccessors[i](this);
}
// Method that is called by the declaring type to pass an array with the
// MethodInfo of some methods. MyClass then creates delegates for these
// methods and stores them in the directReadAccessors array.
public static void InitializeClass(MethodInfo[] directReadAccessorsMInfo) {
int length = directReadAccessorsMInfo.Length;
Type[] typeArguments = new Type[] { typeof(MyClass) };
directReadAccessors = new DirectReadAccessor<MyClass>[length];
// For each method in directReadAccessorsMInfo...
for (int i = 0; i < length; i++) {
// Create a delegate and store it in directReadAccessors.
directReadAccessors[i] = (DirectReadAccessor<MyClass>)
Delegate.CreateDelegate(
DirectReadAccessor<MyClass>, // Type of the delegate.
null, // Specify null first argument so that it's
// *open* instance.
directReadAccessorsMInfo[i].MakeGenericMethod(typeArguments) // The method.
);
}
}
}
*on open instance delegates.
This has been tricky because MyClass doesn't exist when I'm trying to declare the field directReadAccessors, which is of type DirectReadAccessor[], or when I emit the method InitalizeClass, which again uses MyClass, that doesn't exist yet (that's what I'm creating). However, I've managed to do all this, but now I'm having trouble with method DirectRead, since I don't know how to call the delegate once I have it on the stack. Apparently what I need is the following emit:
ilGenerator.Emit(OpCodes.Callvirt, invokeMInfo);
where invokeMInfo is the method Invoke on DirectReadAccessor, and which I should obtain like so:
MethodInfo invokeMInfo = typeof(DirectReadAccessor<MyClass>).GetMethod(
"Invoke", // Name of the method.
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, // Binding attributes.
null, // Binder.
new Type[] { typeof(MyClass) }, // Types of the arguments.
null // Modifiers for the arguments.
);
Again, the problem is that neither MyClass nor DirectReadAccessor exist yet. I have the TypeBuilder for MyClass and the unfinished DirectReadAccessor type, which I've created like this:
directReadAccessorType = typeof(DirectReadAccessor<>).MakeGenericType(typeBuilder);
But if I try to call GetMethod("Invoke", ....) on directReadAccessorType as shown above I get a NotSupportedException, because I cannot obtain the method Invoke for an unfinished type. I've tested this assumption by making the same call after finalizing the type with:
typeBuilder.CreateType();
And indeed I do not get the exception in that case. However, I need to be able to get the Invoke method's MethodInfo before finalizing the type, while I'm emitting the code for InitializeClass.
It's a strange situation: I'll have the delegate when I need it, but I cannot produce the code to invoke it. Can anyone offer any help?
Thanks so much, and sorry for the lengthy post.
That's a tricky problem. I think that you should be able to use TypeBuilder.GetMethod to get the MethodInfo you need, using a call along the lines of
TypeBuilder.GetMethod(directReadAccessorType,
typeof(DirectReadAccessor<>).GetMethod("Invoke"));
Have you tried to compile the generic code and look at it using ILDASM ? It should show you the correct IL and hopefully the right emit to generate.
Would it make sense to minimize the amount of code in the generated class ?
By that, I mean that the generated class could implement an interface that gives access to its data. Through it, you could implement additional features that could be coded in C# instead of IL.