32

For properties there are GetGetMethod and GetSetMethod so that I can do:

Getter = (Func<S, T>)Delegate.CreateDelegate(typeof(Func<S, T>), 
                                             propertyInfo.GetGetMethod());

and

Setter = (Action<S, T>)Delegate.CreateDelegate(typeof(Action<S, T>), 
                                               propertyInfo.GetSetMethod());

But how do I go about FieldInfos?

I am not looking for delegates to GetValue and SetValue (which means I will be invoking reflection each time)

Getter = s => (T)fieldInfo.GetValue(s);
Setter = (s, t) => (T)fieldInfo.SetValue(s, t);

but if there is a CreateDelegate approach here? I mean since assignments return a value, can I treat assignments like a method? If so is there a MethodInfo handle for it? In other words how do I pass the right MethodInfo of setting and getting a value from a member field to CreateDelegate method so that I get a delegate back with which I can read and write to fields directly?

Getter = (Func<S, T>)Delegate.CreateDelegate(typeof(Func<S, T>), fieldInfo.??);
Setter = (Action<S, T>)Delegate.CreateDelegate(typeof(Action<S, T>), fieldInfo.??);

I can build expression and compile it, but I am looking for something simpler. In the end I don't mind going the expression route if there is no answer for the asked question, as shown below:

var instExp = Expression.Parameter(typeof(S));
var fieldExp = Expression.Field(instExp, fieldInfo);
Getter = Expression.Lambda<Func<S, T>>(fieldExp, instExp).Compile();
if (!fieldInfo.IsInitOnly)
{
    var valueExp = Expression.Parameter(typeof(T));
    Setter = Expression.Lambda<Action<S, T>>(Expression.Assign(fieldExp, valueExp), instExp, valueExp).Compile();
}

Or am I after the nonexistent (since I have nowhere seen something like that yet) ?

Community
  • 1
  • 1
nawfal
  • 70,104
  • 56
  • 326
  • 368
  • Is there some reason why you need to call `Delegate.CreateDelegate`? You already have a delegate with `getter`. Simply calling `getter(myInstanceOfT)` will invoke the `fieldInfo.GetValue` method and return you the value. – Chris Sinclair Apr 18 '13 at 01:51
  • @ChrisSinclair yes performance is the key. See this thread: http://stackoverflow.com/questions/8087611/delegate-for-generic-property-getsetmethod – nawfal Apr 18 '13 at 02:19
  • This `Func getter = s => (T)fieldInfo.GetValue(s);` all you can do, because field doesn't have the setter\getter method as it is in a property. If performance is the key I recommend to use the Expression. – Vyacheslav Volkov Apr 18 '13 at 03:09
  • @vvs0205 I know I will have to eventually use expression if I can't pass a methodinfo for setting and getting values to a field. Just seeing if it can be simulated. – nawfal Apr 18 '13 at 09:25
  • Do you also want the delegate to work for readonly fields and private fields? – Martin Mulder Apr 25 '13 at 19:32
  • @MartinMulder readonly fields should only be readable. For private fields, yes (but I will use only in the *private* context - I mean inside the class itself). Basically I will respect the protection/privacy/visibility – nawfal Apr 25 '13 at 19:35
  • 1
    @newfal: Take a look at my answer. You can modify it anyway you want to prefect readonly fields to stay readonly or you can forcibly overwrite them. Having these two little functions saved me a lot of time. – Martin Mulder Apr 26 '13 at 07:44
  • @MartinMulder I have already looked at your answer since it was posted. And as I said, it's only something I already posted in my question. – nawfal Apr 26 '13 at 08:36
  • @newfal: True... you already suggested in this direction. But you asked for something as simple as: '(Func)Delegate.CreateDelegate(typeof(Func), fieldInfo.?);' Such functions do not exists! I just suggested to create such a 'simple' function yourself. This way you prevent having Expressions everywhere in code and you can just call that simple function, exactly what you asked for. Now if the BODY of that function can be simpler, the anwer is simple: NO! (having the opion that IL is not simpler). Perhapse I misunderstand your question: Do you want a simpler call to or a simpler body? – Martin Mulder Apr 26 '13 at 08:56
  • @MartinMulder Honestly I was after a `get-set` method pair for fieldinfo (similar to properties) and not at all after a function that is named `CreateDelegate` but internally goes the expression route. That was not the purport of the question. If you took it so, I'm sorry. I accept I may not have worded the question as clearly as you would have wanted. I did not ask a question not knowing how to refactor a method and give it a name. Certainly not to open a bounty for it. – nawfal Apr 26 '13 at 13:20
  • @Newfal: Well... in that case the answer is simple: No, there are no existing (fast) Get/Set-methods for a field, only the (slow) GetValue/SetValue of FieldInfo. – Martin Mulder Apr 27 '13 at 08:00

8 Answers8

32

As Peter Ritchie suggested, you can compile your own code at runtime. The method will be compiled as soon as you invoke the delegate for the first time. So the first call will be slow, but any subsequent call will be as fast as you can get in .NET without unmanaged pointers/unions. Except for the first call, the delegate is around 500 times faster than FieldInfo directly.

class DemoProgram
{
    class Target
    {
        private int value;
    }

    static void Main(string[] args)
    {
        FieldInfo valueField = typeof(Target).GetFields(BindingFlags.NonPublic| BindingFlags.Instance).First();
        var getValue = CreateGetter<Target, int>(valueField);
        var setValue = CreateSetter<Target, int>(valueField);

        Target target = new Target();

        setValue(target, 42);
        Console.WriteLine(getValue(target));
    }

    static Func<S, T> CreateGetter<S, T>(FieldInfo field)
    {
        string methodName = field.ReflectedType.FullName + ".get_" + field.Name;
        DynamicMethod setterMethod = new DynamicMethod(methodName, typeof(T), new Type[1] { typeof(S) }, true);
        ILGenerator gen = setterMethod.GetILGenerator();
        if (field.IsStatic)
        {
            gen.Emit(OpCodes.Ldsfld, field);
        }
        else
        {
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Ldfld, field);
        }
        gen.Emit(OpCodes.Ret);
        return (Func<S, T>)setterMethod.CreateDelegate(typeof(Func<S, T>));
    }

    static Action<S, T> CreateSetter<S,T>(FieldInfo field)
    {
        string methodName = field.ReflectedType.FullName+".set_"+field.Name;
        DynamicMethod setterMethod = new DynamicMethod(methodName, null, new Type[2]{typeof(S),typeof(T)},true);
        ILGenerator gen = setterMethod.GetILGenerator();
        if (field.IsStatic)
        {
            gen.Emit(OpCodes.Ldarg_1);
            gen.Emit(OpCodes.Stsfld, field);
        }
        else
        {
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Ldarg_1);
            gen.Emit(OpCodes.Stfld, field);
        }
        gen.Emit(OpCodes.Ret);
        return (Action<S, T>)setterMethod.CreateDelegate(typeof(Action<S, T>));
    }
}

Keep in mind that structs are passed by value. That means an Action<S, T> can not be used to change members of a struct if it is passed by value as the first argument.

Zotta
  • 2,513
  • 1
  • 21
  • 27
  • Its been a 50-50 between yours and Ritchie's answer. In the end I decided to choose his answer as correct since it gave the correct answer to the question; awarded you the bounty for the effort. – nawfal Apr 27 '13 at 11:18
  • When the field is static (there's no 'this' pointer) why are you using Ldarg_1 instead of Ldarg_0? – vexe Feb 09 '15 at 20:27
  • Because the delegate is always (S obj, T value), even when the field is static. The user will pass null or something as the first argument. – Zotta Feb 15 '15 at 21:39
  • 1
    To avoid a runtime error, I had to add a `field.Module` parameter, like this: `var getMethod = new DynamicMethod(methodName, typeof(TMember), new[] { typeof(TObject) }, field.Module, true);` – Timo Apr 05 '17 at 12:48
22

[2019 edit: Since this post has always been one of my favorites, it is bittersweet to note that the approach I show here has been wholly superseded, in my own projects, by a newer, entirely different, and much sleeker technique, which I detail at this answer].


Using the new “ref return” feature in C# 7.0 can make the process of creating and using runtime dynamically-generated get/set accessors much simpler and syntactically transparent. Instead of having to use DynamicMethod to emit separate getter and setter functions for accessing the field, you can now have a single method that returns a managed pointer-type reference to the field, es­sentially a single accessor that (in turn) enables convenient, ad-hoc get a̲n̲d̲ set access. Below, I provide a helper utility function which simplifies generating a ByRef getter function for any arbitrary (i.e. private) instance field in any class.

      ➜ For “just the code,” skip to note below.

As a running example, let's say we want to access a private instance field m_iPrivate, an int defined in the class OfInterestClass:

public class OfInterestClass
{
    private int m_iPrivate;
};

Next let's assume we have a static field “reference-getter” function that takes a OfInterestClass instance and returns the desired field value by reference using the new C# 7ref return” capability (below, I'll provide code to generate such functions at runtime, via DynamicMethod):

public static ref int __refget_m_iPrivate(this OfInterestClass obj)
{
     /// ...
}

Such a function (“ref-getter,” let's say) is all we need in order to to have full read/write access to the private field. In the following examples, note especially the setter-invoking operation—and the de­monstrations of using the (i.e.) ++ and += operators—since applying those operators directly to a method call may look a little unusual if you're not up-to-speed on C#7.

void MyFunction(OfInterestClass oic)
{
    int the_value = oic.__refget_m_iPrivate();      // 'get'
    oic.__refget_m_iPrivate() = the_value + 100;    // 'set'

    /// or simply...
    oic.__refget_m_iPrivate() += 100;                // <-- yes, you can

    oic.__refget_m_iPrivate()++;                     // <-- this too, no problem

    ref int prv = ref oic.__refget_m_iPrivate();     // via "ref-local" in C#7
    prv++;
    foo(ref prv);                                    // all of these directly affect…
    prv = 999;                                       // …field m_iPrivate 'in-situ'
}

As is the point, every operation shown in these examples manipulates m_iPrivate in situ (i.e., directly within its containing instance oic) such that any and all changes are publicly visible there immediately. It's impor­tant to realize that this means that prv, despite being int-typed and locally declared, does not behave like your typical “local” variable. This is especially significant for concur­rent code; not only are changes visible b̲e̲f̲o̲r̲e̲ MyFunction has exited, but now with C# 7, callers have the ability to retain a ref return managed pointer (as a ref local) and thus continue modifying the target for an arbitrarily long time a̲f̲t̲e̲r̲wards (albeit necessarily remaining below the ref-obtaining stack frame, that is).

Of course a main and obvious advantage of using a managed pointer here—and elsewhere in gen­eral—is that it continues to remain valid (again, within its stack frame's lifetime), even as oic—itself a reference-type instance allocated in the GC heap—may be moved around during garbage collection. This is a gigantic difference versus na­tive pointers.

As sketched above, the ref-getter is a static extension method that can be declared and/or used from anywhere. But if you're able to create your own class that's derived from OfInterestClass (that is, if OfInterestClass isn't sealed), you can make this even nicer. In a derived class, you can expose C# syntax for using the base class's private field as if it were a public field of your derived class. To do this, just add a C# read-only ref return property to your class which binds the static ref-getter method to the current instance this:

public ref int m_iPrivate => ref __refget_m_iPrivate(this);

Here, the property is made public so anybody can access the field (via a reference to our derived class). We've essentially publicly published the private field from the base class. Now, in the derived class (or elsewhere, as appropriate) you can do any or all of the following:

int v = m_iPrivate;                             // get the value

m_iPrivate = 1234;                              // set the value

m_iPrivate++;                                   // increment it

ref int pi = ref m_iPrivate;                    // reference as C# 7 ref local

v = Interlocked.Exchange(ref m_iPrivate, 9999); // even do in-situ atomic operations on it!

As you can see, because the property, like the earlier method, also has a by reference return value, it behaves almost exactly like a field does.

So now for the details. How do you create the static ref-getter function that I showed above? Using DynamicMethod, this should be trivial. For example, here is the IL code for a traditional (by-value) static getter function:

// static int get_iPrivate(OfInterestClass oic) => oic.m_iPrivate;
IL_0000: ldarg.0    
IL_0001: ldfld Int32 m_iPrivate/OfInterestClass
IL_0006: ret       

And here is the IL code that we want instead (ref-return):

// static ref int refget_iPrivate(OfInterestClass oic) => ref oic.m_iPrivate;
IL_0000: ldarg.0    
IL_0001: ldfld̲a Int32 m_iPrivate/OfInterestClass
IL_0006: ret     

The only difference from the by-value getter is that we are using the ldflda (load field address) opcode instead of ldfld (load field). So if you're well-practiced with DynamicMethod it should be no problem, right?

Wrong!...
    unfortunately DynamicMethod does not allow a by-ref return value!

If you try to call the DynamicMethod constructor specifying a ByRef type as the return value...

var dm = new DynamicMethod(
        "",                                 // method name
        typeof(int).MakeByRefType(),        // by-ref return type   <-- ERROR
        new[] { typeof(OfInterestClass) },  // argument type(s)
        typeof(OfInterestClass),            // owner type
        true);                              // private access

...the function throws NotSupportedException with the following message:

The return Type contains some invalid type (i.e. null, ByRef)

Apparently, this function did not get the memo on C#7 and ref-return. Fortunately, I found a simple workaround that gets it working. If you pass a non-ref type into the constructor as a temporary "dummy," but then immediately afterwards use reflection on the newly-created DynamicMethod instance to change its m_returnType private field to be the ByRef-type type (sic.) that you actually want, then everything seems to work just fine.

To speed things up, I'll cut to the completed generic method which automates the whole process of by creating/returning a static ref-getter function for the private instance field of type U, having the supplied name, and defined in class T.


If you just want the complete working code, copy from below this point to the end


First we have to define a delegate that represents the ref-getter, since a Func<T,TResult> delegate with ByRef usage can't be declared. Fortunately, the older delegate syntax does work for doing so (phew!).

public delegate ref U RefGetter<T, U>(T obj);

Place the delegate, along with the following static function in a centralized utility class where both can be accessed throughout your project. Here's the final ref-getter creation function which can be used to create a static ref-getter for the so-named instance field in any class.

public static RefGetter<T, U> create_refgetter<T, U>(String s_field)
{
    const BindingFlags bf = BindingFlags.NonPublic |
                            BindingFlags.Instance |
                            BindingFlags.DeclaredOnly;

    var fi = typeof(T).GetField(s_field, bf);
    if (fi == null)
        throw new MissingFieldException(typeof(T).Name, s_field);

    var s_name = "__refget_" + typeof(T).Name + "_fi_" + fi.Name;

    // workaround for using ref-return with DynamicMethod:
    //   a.) initialize with dummy return value
    var dm = new DynamicMethod(s_name, typeof(U), new[] { typeof(T) }, typeof(T), true);

    //   b.) replace with desired 'ByRef' return value
    dm.GetType().GetField("m_returnType", bf).SetValue(dm, typeof(U).MakeByRefType());

    var il = dm.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldflda, fi);
    il.Emit(OpCodes.Ret);

    return (RefGetter<T, U>)dm.CreateDelegate(typeof(RefGetter<T, U>));
}

Returning now to outset of this article, we can easily provide the __refget_m_iPrivate function that got everything started. Instead of a static function written directly in C#, we will use the static ref-getter creation function to create the function body at runtime and store it in a static delegate-typed field (with the same signature). The syntax for calling it in the instance property (as shown above, and repeated below) or elsewhere is the same as if the compiler had been able to write the function.

Finally, to cache the dynamically-created ref-getter delegate, place the following line in any static class of your choice. Replace OfInterestClass with the type of the base class, int with the field type of the private field, and change the string argument to match the name of the private field. If you aren't able to create your own class derived from OfInterestClass (or don't want to), you're done; just make this field public and you can call it like a function, passing any OfInterestClass instance to get a reference which lets you read, write, or monitor its int-valued private field "m_iPrivate."

// Static delegate instance of ref-getter method, statically initialized.
// Requires an 'OfInterestClass' instance argument to be provided by caller.
static RefGetter<OfInterestClass, int> __refget_m_iPrivate = 
                                create_refgetter<OfInterestClass, int>("m_iPrivate");

Optionally, if you want to publish the hidden field with a cleaner or more natural syntax, you can define a (non-static) proxy class of your own which either contains an instance of—or perhaps even better (if possible), derives from—the field hiding class OfInterestClass. Instead of deploying the line of code previously shown globally in a static class, place it in your proxy class instead, and then also add the following line:

// optional: ref-getter as an instance property (no 'this' argument required)
public ref int m_iPrivate => ref __refget_m_iPrivate(this);
Glenn Slayden
  • 17,543
  • 3
  • 114
  • 108
  • ...this...is....AMAZING!! I wish StackOverflow had a way to send people some of their points as a thank you lol. Genius hack around the ref return restriction in DynamicMethod...I would have definitely given up at that point. Did you report the shortcoming anywhere so it gets addressed? – Mike Marynowski Nov 24 '17 at 03:57
  • @MikeMarynowski Thanks! Although [not ideal](https://meta.stackexchange.com/questions/192240), typically [people use bounties](https://meta.stackexchange.com/questions/144028) for that purpose. – Glenn Slayden Nov 24 '17 at 08:51
  • I didn't realize I could put a bounty on another question that already had an answer and award it to any of the answers I wanted to. You got a +50 incoming in 23 hours for making my life SOOO much easier solving a problem with this. – Mike Marynowski Nov 24 '17 at 14:07
  • Brilliant answer, this is what makes SO great! I was trying to get a pointer to a primitive field via reflection and this approach allowed me to do exactly that. Thanks. – user425678 Jun 09 '18 at 09:58
  • 1
    Just a small fix for .NET 3.5 (for those of us using Unity and mono). DynamicMethod has no field "m_returnType" but it is called "returnType" instead. So I would refactor that to `var f_returnType = dm.GetType().GetField("m_returnType", bf); if (f_returnType == null) f_returnType = dm.GetType().GetField("returnType", bf); f_returnType.SetValue(dm, typeof(U).MakeByRefType());` – Andreas Pardeike Aug 06 '18 at 20:18
  • @GlennSlayden Neat :) But is there a way to also do this in an Aot environment (like IL2CPP)? Is it possible to somehow "emulate" `Ldflda`? Maybe using something like `System.Runtime.CompilerServices.Unsafe`? – Riki May 25 '19 at 08:08
  • Are there any advantages to using `ref` when you only want read-only access a field that stores a reference-type? – Dai Aug 15 '19 at 16:52
  • 1
    @Dai No, not really. The IL for ref access will use superfluous indirection which would be unnecessary for simply grabbing a handle-valued field value, if you never need to alter that field value. – Glenn Slayden Aug 15 '19 at 22:45
  • 2
    @GlennSlayden P.S. The reflection hack isn't needed on newer .NET Core runtimes. See https://github.com/dotnet/corefx/issues/30753 – Mike Marynowski Sep 02 '19 at 16:25
11

Field access isn't performed via a method (like getters and setters)--it's performed with an IL instruction--so there's nothing you can assign to a delegate. you'll have to use the expression route to create a "block" of code (effectively IL) that can be assigned to a delegate.

Peter Ritchie
  • 35,463
  • 9
  • 80
  • 98
  • You're right I think. And there is nothing *reflection-ish* about it I believe, since assigning and reading via compiled expression were blazingly fast.. – nawfal Apr 20 '13 at 17:24
  • Yes, a compiled expression should b e just as fast as if you wrote you own method to access the field and compiled it normally. – Peter Ritchie Apr 20 '13 at 17:53
  • 2
    Peter, I had once benchmarked compiled expression vs createdelegate for properties in getting and setting and createdelegate was the clear winner, hence this question – nawfal Apr 20 '13 at 19:00
  • 1
    @nawfal Yes, but you need a method to use CreateDelegate--without that you have to create your own at compile-time, or at runtime (with compiled expressions or codegen--I don't think a compiled expression would be any faster than codegen). – Peter Ritchie Apr 20 '13 at 22:12
  • I think that sums up as an answer, but I will wait for other answers as well before awarding bounty. I was waiting for a definitive take on it from the community. – nawfal Apr 21 '13 at 04:50
10

No there is no easy way to create a delegate to get/set a field.

You will have to make your own code to provide that functionallity. I would suggest two functions in a shared library to provide this.

Using your code (in this example I only show the creation of the get-delegate):

static public class FieldInfoExtensions
{
    static public Func<S, T> CreateGetFieldDelegate<S, T>(this FieldInfo fieldInfo)
    {
        var instExp = Expression.Parameter(typeof(S));
        var fieldExp = Expression.Field(instExp, fieldInfo);
        return Expression.Lambda<Func<S, T>>(fieldExp, instExp).Compile();
    }
}

This makes it easy to create a get-delegate from a FieldInfo (assuming the field is of type int):

Func<MyClass, int> getter = typeof(MyClass).GetField("MyField").CreateGetFieldDelegate<MyClass, int>();

Or if we change your code a little bit:

static public class TypeExtensions
{
    static public Func<S, T> CreateGetFieldDelegate<S, T>(this Type type, string fieldName)
    {
        var instExp = Expression.Parameter(type);
        var fieldExp = Expression.Field(instExp, fieldName);
        return Expression.Lambda<Func<S, T>>(fieldExp, instExp).Compile();
    }
}

This makes it even more easy:

Func<MyClass, int> getter = typeof(MyClass).CreateGetFieldDelegate<MyClass, int>("MyField");

It is also possible to create these delegates using IL, but that code would be more complex and does not have much more performance, if any.

Martin Mulder
  • 12,642
  • 3
  • 25
  • 54
  • `No there is no easy way to create a delegate to get/set a field.` that answers my question, (already added by Ritchie). The rest is merely refactoring the code I already posted in the question to useful methods. Nevertheless thanks for chiming in. Btw, you can avoid `(Func)` casts in your helper functions. nothing much, just readability – nawfal Apr 21 '13 at 22:34
2

I'm not aware if you would use Expression, then why avoiding reflection? Most operations of Expression rely on reflection.

GetValue and SetValue themself are the get method and set method, for the fields, but they are not for any specific field.

Fields are not like properties, they are fields, and there's no reason to generate get/set methods for each one. However, the type may vary with different field, and thus GetValue and SetValue are defined the parameter/return value as object for variance. GetValue is even a abstract method, that is, for every class(still reflection) overriding it, must be within the identical signature.

If you don't type them, then the following code should do:

public static void SomeMethod(FieldInfo fieldInfo) {
    var Getter=(Func<object, object>)fieldInfo.GetValue;
    var Setter=(Action<object, object>)fieldInfo.SetValue;
}

but if you want, there's a constrained way:

public static void SomeMethod<S, T>(FieldInfo fieldInfo)
    where S: class
    where T: class {
    var Getter=(Func<S, object>)fieldInfo.GetValue;
    var Setter=(Action<S, T>)fieldInfo.SetValue;
}

For the reason that the Getter still be Func<S, object>, you might want to have a look of:

Covariance and Contravariance in C#, Part Three: Method Group Conversion Variance on Mr. Lippert's blog.

Ken Kin
  • 4,503
  • 3
  • 38
  • 76
  • 1
    You: "then why avoiding reflection?" Answer: Yes, expressions also make use of reflection. Reflection is slow, so we have to avoid it. But you can use reflection and/or expressions to create a delegate. Once the delegate is created which DIRECTLY calls a method or DIRECTLY modifies a field, without using reflection, you have a very fast solution. So creating a delegate this way is slow, but calling it a million times is not. – Martin Mulder Apr 26 '13 at 07:38
  • 1
    @MartinMulder: Well, I believe there's no such delegate we can create for fields .. and maybe some workaround .. `OpCodes.Callvirt` – Ken Kin Apr 26 '13 at 08:09
  • Depends how you look at it. A field is always written by a piece of code. So yes, a piece of code has to be present or has to be created. Once the piece of code is known, you can create a delegate to it. Creating this code (with Expressions) is rather slow, but once it is in place, it is fast. – Martin Mulder Apr 26 '13 at 08:50
  • @MartinMulder: As I mentioned in the answer, I cannot find more than `GetValue` and `SetValue`; but these methods are not binded to specific classes. So it doesn't depends on `how I ..`, it depends on how the language is implemented .. – Ken Kin Apr 26 '13 at 09:48
  • 1
    `GetValue` and `SetValue` are both part of the reflection world. Creating a delegate to these function is fast. Calling them is still slow, because they are generic (for all kinds of fields). Calling them a million times is 1.000.000 x slow. And than I am not even talking about boxing and unboxing. If you create a piece of code with generic you actuall create functions LIKE `GetValue` and `SetValue`, but only specialized and high-speed. So in both cases your have a piece of code, but what piece of code would you prefer? – Martin Mulder Apr 26 '13 at 09:54
  • @MartinMulder: ... seems I'm not make myself clear, I'm saying AFAIK there's not something like that for fields .., however, I'm now trying to trace deeper in reflection to find. – Ken Kin Apr 26 '13 at 10:03
  • @KenKin, this is a call to reflection each time. Though it technically answers my question, it was against the spirit of my question, ie performance :) – nawfal Apr 27 '13 at 10:58
  • @nawfal: I know .. as the answers told, there are not something for fields as for properties naturely, you would need to write the code. – Ken Kin Apr 27 '13 at 14:17
2

ref return restriction in DynamicMethod seems to be gone at least on v4.0.30319.

Modified this answer by Glenn Slayden with info from microsoft docs:

using System;
using System.Reflection;
using System.Reflection.Emit;

namespace ConsoleApp {
    public class MyClass {
        private int privateInt = 6;
    }

    internal static class Program {
        private delegate ref TReturn OneParameter<TReturn, in TParameter0>(TParameter0 p0);

        private static void Main() {
            var myClass = new MyClass();

            var method = new DynamicMethod(
                "methodName",
                typeof(int).MakeByRefType(), // <- MakeByRefType() here
                new[] {typeof(MyClass)}, 
                typeof(MyClass), 
                true); // skip visibility


            const BindingFlags bindings = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

            var il = method.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldflda, typeof(MyClass).GetField("privateInt", bindings));
            il.Emit(OpCodes.Ret);

            var getPrivateInt = (OneParameter<int, MyClass>) method.CreateDelegate(typeof(OneParameter<int, MyClass>));

            Console.WriteLine(typeof(string).Assembly.ImageRuntimeVersion);
            Console.WriteLine(getPrivateInt(myClass));
        }
    }
}

Outputs:

6
1

Here is an another option for creating a delegate when you are working with objects (don't know specific type of a field). Though it is slower if field is a structure (because of boxing).

public static class ReflectionUtility
{
    public static Func<object, object> CompileGetter(this FieldInfo field)
    {
        string methodName = field.ReflectedType.FullName + ".get_" + field.Name;
        DynamicMethod setterMethod = new DynamicMethod(methodName, typeof(object), new[] { typeof(object) }, true);
        ILGenerator gen = setterMethod.GetILGenerator();
        if (field.IsStatic)
        {
            gen.Emit(OpCodes.Ldsfld, field);
            gen.Emit(field.FieldType.IsClass ? OpCodes.Castclass : OpCodes.Box, field.FieldType);
        }
        else
        {
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Castclass, field.DeclaringType);
            gen.Emit(OpCodes.Ldfld, field);
            gen.Emit(field.FieldType.IsClass ? OpCodes.Castclass : OpCodes.Box, field.FieldType);
        }
        gen.Emit(OpCodes.Ret);
        return (Func<object, object>)setterMethod.CreateDelegate(typeof(Func<object, object>));
    }

    public static Action<object, object> CompileSetter(this FieldInfo field)
    {
        string methodName = field.ReflectedType.FullName + ".set_" + field.Name;
        DynamicMethod setterMethod = new DynamicMethod(methodName, null, new[] { typeof(object), typeof(object) }, true);
        ILGenerator gen = setterMethod.GetILGenerator();
        if (field.IsStatic)
        {
            gen.Emit(OpCodes.Ldarg_1);
            gen.Emit(field.FieldType.IsClass ? OpCodes.Castclass : OpCodes.Unbox_Any, field.FieldType);
            gen.Emit(OpCodes.Stsfld, field);
        }
        else
        {
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Castclass, field.DeclaringType);
            gen.Emit(OpCodes.Ldarg_1);
            gen.Emit(field.FieldType.IsClass ? OpCodes.Castclass : OpCodes.Unbox_Any, field.FieldType);
            gen.Emit(OpCodes.Stfld, field);
        }
        gen.Emit(OpCodes.Ret);
        return (Action<object, object>)setterMethod.CreateDelegate(typeof(Action<object, object>));
    }
}
1

Just to add more ways of doing it :D

 public static Func<T, TResult> CreatePropertyOrFieldReaderDelegate<T, TResult>(string field)
        {
            var input = Expression.Parameter(typeof(T));
            return Expression.Lambda<Func<T, TResult>>(Expression.PropertyOrField(input, field), input).Compile();
        }

This will create a method that returns the value..

TEST CASE

class Testing {
  public int Data = 2;
  public string PropData { get; } = "Default";
 }


  [Fact]
  public void CreateSingleFieldReader()
        {
            var a = ReflectionHelper.CreatePropertyOrFieldReaderDelegate<Testing, int>("Data");
            Assert.Equal(2, a(new Testing()));

        }
PEtter
  • 806
  • 9
  • 22