Click here to Skip to main content
Click here to Skip to main content

Fast Dynamic Property Access with C#

By , 22 Mar 2005
 

Sample Image - Fast_Dynamic_Properties.png

Introduction

Reflection is very useful for dynamic processing. However, if you have to repeatedly reflect on a property, say in a processing loop, you'll soon find that it can lead to performance problems. I ran into this particular problem in developing a rules engine that will be able to validate collections. I thought I would share this snippet of code, since I think it could be used in a variety of situations.

In this article I'll provide a fast, alternative solution for dynamic property access.

Implementation

My goal was to develop a class that could create a Type at runtime for direct access to the Get and Set methods of a property. This class would be provided with the target object Type and the property name it should access. I had considered runtime compiling, but then I learned about Reflection.Emit and its ability to create types at runtime through the use of MSIL. This was my first experience writing MSIL code and I found Ben Ratzlaff's Populating a PropertyGrid using Reflection.Emit to be a very helpful start.

In order to be able to compile code against against a Type that will be generated at runtime, an interface had to be created to define the generated types.

/// <summary>
/// The IPropertyAccessor interface defines a property
/// accessor.
/// </summary>
public interface IPropertyAccessor
{
    /// <summary>
    /// Gets the value stored in the property for
    /// the specified target.
    /// </summary>
    /// <param name="target">Object to retrieve
    /// the property from.</param>
    /// <returns>Property value.</returns>
    object Get(object target);
    /// <summary>
    /// Sets the value for the property of
    /// the specified target.
    /// </summary>
    /// <param name="target">Object to set the
    /// property on.</param>
    /// <param name="value">Property value.</param>
    void Set(object target, object value);
}

The concrete PropertyAccessor class generates a Type at runtime that conforms to this interface and serves as a proxy layer to the generated Type. In its constructor it simply needs to be provided with the target object Type and the name of the property it should provide access to. All of the Reflection.Emit code is performed in the EmitAssembly method.

/// <summary>
/// The PropertyAccessor class provides fast dynamic access
/// to a property of a specified target class.
/// </summary>
public class PropertyAccessor : IPropertyAccessor
{
    /// <summary>
    /// Creates a new property accessor.
    /// </summary>
    /// <param name="targetType">Target object type.</param>
    /// <param name="property">Property name.</param>
    public PropertyAccessor(Type targetType, string property)
    {
        this.mTargetType = targetType;
        this.mProperty = property;
        PropertyInfo propertyInfo = 
            targetType.GetProperty(property);
        //
        // Make sure the property exists
        //
        if(propertyInfo == null)
        {
            throw new 
              PropertyAccessorException(string.Format("Property \"{0}\" does" + 
              " not exist for type " + "{1}.", property, targetType));
        }
        else
        {
            this.mCanRead = propertyInfo.CanRead;
            this.mCanWrite = propertyInfo.CanWrite;
            this.mPropertyType = propertyInfo.PropertyType;
        }
    }

    /// <summary>
    /// Gets the property value from the specified target.
    /// </summary>
    /// <param name="target">Target object.</param>
    /// <returns>Property value.</returns>
    public object Get(object target)
    {
        if(mCanRead)
        {
            if(this.mEmittedPropertyAccessor == null)
            {
                this.Init();
            }
            return this.mEmittedPropertyAccessor.Get(target);
        }
        else
        {
            throw new 
              PropertyAccessorException(string.Format("Property \"{0}\" does" + 
              " not have a get method.", mProperty));
        }
    }

    /// <summary>
    /// Sets the property for the specified target.
    /// </summary>
    /// <param name="target">Target object.</param>
    /// <param name="value">Value to set.</param>
    public void Set(object target, object value)
    {
        if(mCanWrite)
        {
            if(this.mEmittedPropertyAccessor == null)
            {
                this.Init();
            }
            //
            // Set the property value
            //
            this.mEmittedPropertyAccessor.Set(target, value);
        }
        else
        {
            throw new 
              PropertyAccessorException(string.Format("Property \"{0}\" does" + 
              " not have a set method.", mProperty));
        }
    }

    /// <summary>
    /// Whether or not the Property supports read access.
    /// </summary>
    public bool CanRead
    {
        get
        {
            return this.mCanRead;
        }
    }

    /// <summary>
    /// Whether or not the Property supports write access.
    /// </summary>
    public bool CanWrite
    {
        get
        {
            return this.mCanWrite;
        }
    }

    /// <summary>
    /// The Type of object this property accessor was
    /// created for.
    /// </summary>
    public Type TargetType
    {
        get
        {
            return this.mTargetType;
        }
    }

    /// <summary>
    /// The Type of the Property being accessed.
    /// </summary>
    public Type PropertyType
    {
        get
        {
            return this.mPropertyType;
        }
    }

    private Type mTargetType;
    private string mProperty;
    private Type mPropertyType;
    private IPropertyAccessor mEmittedPropertyAccessor;
    private Hashtable mTypeHash;
    private bool mCanRead;
    private bool mCanWrite;

    /// <summary>
    /// This method generates creates a new assembly containing
    /// the Type that will provide dynamic access.
    /// </summary>
    private void Init()
    {
        this.InitTypes();
        // Create the assembly and an instance of the 
        // property accessor class.
        Assembly assembly = EmitAssembly();
        mEmittedPropertyAccessor = 
          assembly.CreateInstance("Property") as IPropertyAccessor;
        if(mEmittedPropertyAccessor == null)
        {
            throw new Exception("Unable to create property accessor.");
        }
    }

    /// <summary>
    /// Thanks to Ben Ratzlaff for this snippet of code
    /// http://www.codeproject.com/cs/miscctrl/CustomPropGrid.asp
    /// 
    /// "Initialize a private hashtable with type-opCode pairs 
    /// so i dont have to write a long if/else statement when outputting msil"
    /// </summary>
    private void InitTypes()
    {
        mTypeHash=new Hashtable();
        mTypeHash[typeof(sbyte)]=OpCodes.Ldind_I1;
        mTypeHash[typeof(byte)]=OpCodes.Ldind_U1;
        mTypeHash[typeof(char)]=OpCodes.Ldind_U2;
        mTypeHash[typeof(short)]=OpCodes.Ldind_I2;
        mTypeHash[typeof(ushort)]=OpCodes.Ldind_U2;
        mTypeHash[typeof(int)]=OpCodes.Ldind_I4;
        mTypeHash[typeof(uint)]=OpCodes.Ldind_U4;
        mTypeHash[typeof(long)]=OpCodes.Ldind_I8;
        mTypeHash[typeof(ulong)]=OpCodes.Ldind_I8;
        mTypeHash[typeof(bool)]=OpCodes.Ldind_I1;
        mTypeHash[typeof(double)]=OpCodes.Ldind_R8;
        mTypeHash[typeof(float)]=OpCodes.Ldind_R4;
    }

    /// <summary>
    /// Create an assembly that will provide the get and set methods.
    /// </summary>
    private Assembly EmitAssembly()
    {
        //
        // Create an assembly name
        //
        AssemblyName assemblyName = new AssemblyName();
        assemblyName.Name = "PropertyAccessorAssembly";
        //
        // Create a new assembly with one module
        //
        AssemblyBuilder newAssembly = 
           Thread.GetDomain().DefineDynamicAssembly(assemblyName, 
           AssemblyBuilderAccess.Run);
        ModuleBuilder newModule = 
           newAssembly.DefineDynamicModule("Module");
        //
        // Define a public class named "Property" in the assembly.
        //
        TypeBuilder myType = 
           newModule.DefineType("Property", TypeAttributes.Public);
        //
        // Mark the class as implementing IPropertyAccessor. 
        //
        myType.AddInterfaceImplementation(typeof(IPropertyAccessor));
        // Add a constructor
        ConstructorBuilder constructor = 
           myType.DefineDefaultConstructor(MethodAttributes.Public);
        //
        // Define a method for the get operation. 
        //
        Type[] getParamTypes = new Type[] {typeof(object)};
        Type getReturnType = typeof(object);
        MethodBuilder getMethod = 
          myType.DefineMethod("Get", 
          MethodAttributes.Public | MethodAttributes.Virtual, 
          getReturnType, 
          getParamTypes);
        //
        // From the method, get an ILGenerator. This is used to
        // emit the IL that we want.
        //
        ILGenerator getIL = getMethod.GetILGenerator();

        //
        // Emit the IL. 
        //
        MethodInfo targetGetMethod = this.mTargetType.GetMethod("get_" + 
                                                    this.mProperty);
        if(targetGetMethod != null)
        {
            getIL.DeclareLocal(typeof(object));
            getIL.Emit(OpCodes.Ldarg_1); //Load the first argument
            //(target object)
            //Cast to the source type
            getIL.Emit(OpCodes.Castclass, this.mTargetType);
            //Get the property value
            getIL.EmitCall(OpCodes.Call, targetGetMethod, null);
            if(targetGetMethod.ReturnType.IsValueType)
            {
                getIL.Emit(OpCodes.Box, targetGetMethod.ReturnType);
                //Box if necessary
            }
            getIL.Emit(OpCodes.Stloc_0); //Store it

            getIL.Emit(OpCodes.Ldloc_0);
        }
        else
        {
            getIL.ThrowException(typeof(MissingMethodException));
        }
        getIL.Emit(OpCodes.Ret);

        //
        // Define a method for the set operation.
        //
        Type[] setParamTypes = new Type[] {typeof(object), typeof(object)};
        Type setReturnType = null;
        MethodBuilder setMethod = 
            myType.DefineMethod("Set", 
           MethodAttributes.Public | MethodAttributes.Virtual, 
           setReturnType, 
           setParamTypes);
        //
        // From the method, get an ILGenerator. This is used to
        // emit the IL that we want.
        //
        ILGenerator setIL = setMethod.GetILGenerator();
        //
        // Emit the IL. 
        //
        MethodInfo targetSetMethod = 
            this.mTargetType.GetMethod("set_" + this.mProperty);
        if(targetSetMethod != null)
        {
            Type paramType = targetSetMethod.GetParameters()[0].ParameterType;
            setIL.DeclareLocal(paramType);
            setIL.Emit(OpCodes.Ldarg_1); //Load the first argument 
            //(target object)
            //Cast to the source type
            setIL.Emit(OpCodes.Castclass, this.mTargetType);            
            setIL.Emit(OpCodes.Ldarg_2); //Load the second argument 
            //(value object)
            if(paramType.IsValueType)
            {
                setIL.Emit(OpCodes.Unbox, paramType); //Unbox it 
                if(mTypeHash[paramType]!=null) //and load
                {
                    OpCode load = (OpCode)mTypeHash[paramType];
                    setIL.Emit(load);
                }
                else
                {
                    setIL.Emit(OpCodes.Ldobj,paramType);
                }
            }
            else
            {
                setIL.Emit(OpCodes.Castclass, paramType); //Cast class
            }

            setIL.EmitCall(OpCodes.Callvirt, 
               targetSetMethod, null); //Set the property value
        }
        else
        {
            setIL.ThrowException(typeof(MissingMethodException));
        }
        setIL.Emit(OpCodes.Ret);
        //
        // Load the type
        //
        myType.CreateType();
        return newAssembly;
    }
}

Discussion

Although the PropertyAccessor class must reflect on the target Type the first time the property is accessed (for either read or write), this reflection only has to be done once. All subsequent calls to Get or Set will use the generated IL code.

Run the sample project for a performance demonstration. I've also included an NUnit test fixture.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

James Nies
Software Developer Astral Softworks, LLC
United States United States
Member
James Nies is a graduate of the University of Wyoming's Department of Computer Science. He is currently employed as a software developer and has been programming in C#, his favorite language, for the last 5 years. James recently formed a small software development and web design company, Astral Softworks, LLC.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionDoes not work for virtual property overridesmemberMember 367761918 Apr '13 - 7:24 
PropertyAccessor fails when trying to dynamically read a property that overrides a virtual property in a base class. Error message: "Operation could destablize the runtime". Please advise.
QuestionMagnifying Property AccessgroupExcellentOrg7 Apr '13 - 10:37 
If I wanted to use this to access many different classes (all of which use reflection), should I create a separate class or somehow add this to the base class?
 
What I am trying to ask is best possible strategy
Socket Rocket

SuggestionUsing of Genericsmemberlordkbc27 Jun '11 - 1:16 
Hi,
 
Take a look on my code. Its use generics to convert parameters and return values. Is limited to classes, structs will not work, interfaces should be work but is not implemented.
Is for read only but can be implemented to write too.
 
I believe that is faster because we don't need emit assemblies. What you think about?
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
 
namespace ConsoleApplication8
{
class Program
{
static void Main(string[] args)
{
var test = new { asValue = 17, asRef = "test" };
var reader = PropertyToDelegate.CreateDelegate(test, test.GetType().GetProperty("asValue").GetGetMethod());
Console.WriteLine(reader(test));
reader = PropertyToDelegate.CreateDelegate(test, test.GetType().GetProperty("asRef").GetGetMethod());
Console.WriteLine(reader(test));
// or
var type = test.GetType();
reader = PropertyToDelegate.CreateDelegate(type, type.GetProperty("asValue").GetGetMethod());
Console.WriteLine(reader(test));
reader = PropertyToDelegate.CreateDelegate(type, type.GetProperty("asRef").GetGetMethod());
Console.WriteLine(reader(test));
Console.ReadLine();
}
}
 
struct structTest
{
public int AsValue { get; set; }
public string AsRef { get; set; }
}
 
public delegate object Reader(object This);
 
static class PropertyToDelegate
{
public static Reader CreateDelegate<T>(T obj, MethodInfo method) where T : class
{
return PropertyToDelegate<T>.CreateDelegate(method);
}
 
public static Reader CreateDelegate(Type type, MethodInfo method)
{
return (Reader) typeof(PropertyToDelegate<>).MakeGenericType(type).GetMethod("CreateDelegate").Invoke(null, new object[] { method });
}
}
 
public static class PropertyToDelegate<T> where T : class
{
public delegate object TReader(T This);
static class BoxerForStructs<S> where S : struct
{
delegate S structReader(T obj);
public static TReader CreateDelegate(MethodInfo method)
{
var del = (structReader)Delegate.CreateDelegate(typeof(structReader), method);
return (T obj) => del(obj);
}
}
 
public static Reader CreateDelegate(MethodInfo method)
{
TReader del;
if (!method.ReturnType.IsValueType)
del = (TReader)Delegate.CreateDelegate(typeof(TReader), method);
else
del = (TReader)typeof(BoxerForStructs<>).MakeGenericType(typeof(T), method.ReturnType).GetMethod("CreateDelegate").Invoke(null, new object[] { method });
return (This) => del((T)This);
}
}
}
GeneralJust thought I'll mention thismemberMartin Lottering17 May '11 - 2:06 
Hi James,
 
I know this is an old thread, but I thought I'll just make an observation for those who care to read reviews:

1. In SampleApp.cs, if I replace the Type.InvokeMember() calls with PropertyInfo.SetValue() and PropertyInfo.GetValue(), those durations are sliced to about 20% - 40% of the original time, provided you set the PropertyInfo once BEFORE the loop begins. I suppose it is because it doesn't have to lookup the property info 1,000,000 times as done in Type.InvokeMember() in the test app.
 
What this means is that the REFLECTION part of the test, which is the slowest, is not optimal.
 
2. If like me, you test the code provided by Tobi (Mr T#), and the generic implementation seems slower, it is only because he used 100,000,000 test cycles instead of 1,000,000 as used by James.
 

BTW, great article, and great code. Very useful. Thanks.
 
Regards,
Martin
QuestionWhat if I want to create the properties dynamicallymemberharsh_godha18 Oct '10 - 7:07 
Hi
As I understand from this code is that, this code calls the properties which are available in the class, I can't create a property. Correct me if i'm wrong.
And what if I want to create properties dynamically.
QuestionDynamic properties work fine but what about dynamic Methods and ctors? [modified]memberDoomii5 Aug '08 - 10:50 
First of all, thanks a lot for this piece of work - It is very helpful in what I am trying to do - Pretty much exactly what i was looking for for a long time! I also extended it with a PropertyAccessorMgr class which auto-manages all property accessors that have been created and only creates a new one if it does not already exist.
 
Now is there an easy way to easily invoke methods or ctors dynamically? I'm not sure if this is the right place to ask but I couldn't seem to find any more info on this matter - And I figured if dynamic property invocation is working, why not methods or ctors? I'm confident someone here must have the answer Smile | :)
 
Edit: I realized 2 things that should be mentioned:
1. The containing class must be public (or -I assume- somehow accessible to the PropertyAccessor).
2. You MUST refer to the actual class of the object whose property you want to evaluate. You cannot use the PropertyAccessor of an underlying type or interface.
 
modified on Tuesday, August 5, 2008 5:08 PM

GeneralVariant with lambdamemberMaskaev9 Apr '08 - 3:05 
Quick variation based on lambda functions.
 
>----------------------------------------
class LambdaPropertyAccessor<T>
   {
      private Dictionary<string, Func<T, object>> propAccessors = new Dictionary<string, Func<T, object>>();
 
      public LambdaPropertyAccessor()
      {
         Type type = typeof (T);
 
         foreach (PropertyInfo pi in type.GetProperties(BindingFlags.Public | BindingFlags.GetProperty
            | BindingFlags.Instance))
         {
            if (!pi.CanRead)
               continue;
 
            ParameterExpression parameter = Expression.Parameter(type, "r");
 
            Expression<Func<T, object>> lambda;
           
            if (pi.PropertyType.IsValueType)
            {
               lambda = Expression.Lambda<Func<T, object>>(
                  Expression.TypeAs(Expression.Property(parameter, pi.Name), typeof(object)), parameter);
            }
            else
            {
               lambda = Expression.Lambda<Func<T, object>>(Expression.Property(parameter, pi.Name), parameter);
            }
 
            propAccessors.Add(pi.Name, lambda.Compile());
         }
      }
 
      public object Get(T obj, string propName)
      {
         return propAccessors[propName](obj);
      }
   }
<----------------------------------------
 
1000000 property gets on integer...
Direct access ms:                                             15,625
PropertyAccessor (Reflection.Emit) ms:               78,125
Reflection ms:                                                   4687,5
Lambda ms:                                                         218,75
 
1000000 property gets on strings...
Direct access ms:                                             15,625
PropertyAccessor (Reflection.Emit) ms:               46,875
Reflection ms:                                                   4765,625
Lambda ms:                                                         203,125
GeneralRe: Variant with lambdamemberAnastasiosyal22 Oct '08 - 2:54 
This is pretty cool. How would you go about implementing a property setter with a lamda?
GeneralRe: Variant with lambdamemberMaskaev22 Oct '08 - 3:37 
Property setter implementation will be a "statement lambda".
I'm not sure that it can be implemented using System.Linq.Expressions.
GeneralRe: Variant with lambdamemberMember 45815422 Jan '10 - 10:59 
You can create dynamic setters.
 
Add the following code to the loop in the constructor:
 

ParameterExpression paramExpT = Expression.Parameter(typeof(T), "instance");
ParameterExpression paramExpObj = Expression.Parameter(typeof(object), "obj");
Action<T, object> setterLambda =
Expression.Lambda<Action<T, object>>(
Expression.Call(paramExpT, pi.GetSetMethod(),
Expression.ConvertChecked(paramExpObj, pi.PropertyType)), paramExpT, paramExpObj)
.Compile();
propSetters.Add(pi.Name, setterLambda);

where propSetters is a member variable:

private Dictionary<string, Action<T, object>> propSetters = new Dictionary<string, Action<T, object>>();

You can then use a Set method to set the value of a property dynamically:

public void Set(T obj, string propName, object value)
{
propSetters[propName](obj, value);
}

Generalpagefile grows boundlesslymemberbobman7719 Sep '07 - 16:35 
I am creating new PropertyAccessor objects in a loop at the rate of about 100 per minute or so. My pagefile grows at a pretty brisk pace until it overwhelms my computer. This is in conjunction with table adapters for a data processing application. when I comment out (Property Adapter) pa.Set(...) in all 18 places, this no longer happens. I guess its the assemblies are being cached there. How do I remove them?
GeneralRe: pagefile grows boundlesslymemberJames Nies22 Sep '07 - 21:33 
If you're not already doing so, I would recommend caching PropertyAccessors so that you never create more than one instance for a given property of a Type. Actually, without doing this, the PropertyAccessor class would be slower than reflection. If caching the PropertyAccessor is not feasible for your particular application, you can unload the cached property assemblies by creating the PropertyAccessors and performing your operations within a new AppDomain. When done with the processing, you can then unload that app domain and the assemblies created under it. However, this introduces code complexity and you'd have to use Remoting to communicate across the AppDomain boundaries.
GeneralModuleBuilder's DefineType throws exception occasionallymemberMandeep Singh Bhatia4 Jun '07 - 23:12 
Hi,
I have been using this code snippet & it worked perfect in .net 1.0 & 1.1. But ever since I ported to 2.0 there is a strange problem:
 
AssemblyBuilder newAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder newModule = newAssembly.DefineDynamicModule("Module");
TypeBuilder myType = newModule.DefineType("Property", TypeAttributes.Public);

 
It throws exception in DefineType.
Say this code is executed 200 time. It will run fine 199 times but once it will throw exception. But it will surely throw exception everytime I run.
And it throws exception only when I debug using VS2005 not when I directly run.
 
Does anyone have any clue to this problem.
 
thanks,
Mandeep.

GeneralQuick Port to GenericsmemberTobias Hertkorn30 May '06 - 15:20 
Hi there!
 
First of all - wow, James, that's excellent work! I have never used Emit before - and here it really makes so much sense!
 
I am using VS 2005 - so I thought, I could do a quick port to .NET 2.0, just to learn something about Emit. Turns out, it is tragically easy to implement it using generics. That is, implementing it using your great code. Seriously, it boils down to removing the casting stuff in your code.
 
But those easy modification give you an additional speed boost and actually cuts the get and set on value types in half! And there is still a significant speed gain on regular objects as well.
 
Have fun downloading GenericPropertyAccessor from my blog, plus an updated test app.
 
For those too lazy to click on the link in my blog - here is the direct link:
GenericPropertyAccessor as Zip
 
Have fun,
Tobi
 
P.S.: I have no idea, what to put in the header of these files?! How do I "clearly mark" that I changed the code but hugely depended on James' work? Is what I did ok, or should I change the header? Help!
 
---
Tobi + C# = T#
QuestionRe: Quick Port to GenericsmemberLeela Krishna20 Jan '07 - 23:34 
First, I thank James very much for the great work!
 
Hi Tobi, the Generic implemation is very nice.
I couldn't pass the property types dynamically to the GenericPropertyAccessor.
Eg:
The below code works fine for string type property.
 
GenericPropertyAccessor propertyAccessor =
new GenericPropertyAccessorstring>("String");
 
but, I am using the above code in the iteration of a collection to display all the property values, so I should pass the property type (higleted) dynamically. any help?

 
LK.
GeneralRe: Quick Port to GenericsmemberTobias Hertkorn13 Apr '07 - 10:52 
Hey Leela,
 
I guess for your kind of situation you would have to use James' original PropertyAccessor. But actually I am not too sure if I understand the situation you are trying to solve.
 
Sorry. Smile | :)
Tobi
 
---
Tobi + C# = T#

GeneralProblem with Value TypesmemberWasp.NET11 May '06 - 22:26 
Hi,
great work, I've been using it and it works fine, but I have a problem: did you ever try accessing properties from a value type? If you try, for example, to get the property "Width" from a System.Drawing.Size, you don't get the value, but a "strange" number that seems to be a memory address... I'm totally ignorant about Emit and I'm not able to see where the problem is, did you verify the same problems and, if you did, do you have some hints about it?
Thanks, bye, Smile | :)
 
Wasp

QuestionModify to getting all propertiesmembersavasorama6 Jan '06 - 3:21 
Hi, this code will be really helpful to me but i also need getting name and value of all public properties. and i also don't have enough knowledge about IL coding. i'll give Type and BindingFlags as parameters instead of property name, and it will give me property info collection.
thanks for your help..
 
-- savas --
AnswerRe: Modify to getting all propertiesmembersgheeren16 May '06 - 6:27 
Given the code as is and the reflection API (you already know about BindingFlags) this should be a piece of cake. Unless you need help coding arrays/collections...?
GeneralCall methodmemberNetTry9 Nov '05 - 3:18 
How to make better (example of reflection) this situation on C#
 
// assembly1
class c1
{
public void method1()
{}
 
public int method2()
{
return 100;
}
}
 
// assembly2
class c2
{
c1 _c1 = new c1();
c3 _c3 = new _c3(_c1);
}
 
// assembly3
class c3(object _o)
{
_o.method1();
int y = 100;
y = y + _o.method2(); // 200
MessageBox.Show(y.ToString()); // 200
}
 

QuestionSetting null values gives an ExceptionmemberPatrick Heymans2 Nov '05 - 21:35 
This is nice stuff, but I have one problem. When I try to set a null value I get a NullReferenceException when the type of the property is a ValueType. Is there a way to change the generated IL for the SetValue method so that it perfoms a null-check first and if so, set the value to the initial value of a ValueType (for example, 0 for ints)? I tried fixing it myself but the IL language is very difficult.
 
Thanks.
 
Pat
 

 


AnswerRe: Setting null values gives an ExceptionmemberJames Nies6 Nov '05 - 11:23 
Rather than put this logic in the IL of the emitted property accessor, you could place it in the Set method of the concrete PropertyAccessor (see code below). It might even make sense to make the PropertyAccessor a base class with a protected abstract DefaultValue property. You could create a concrete implementation for each value type, but then you would also need a factory to create the appropriate property accessor...
 
public void Set(object target, object value)
{
    if(mCanWrite)
    {
        if(this.mEmittedPropertyAccessor == null)
        {
            this.Init();
        }
 
        //
        // If the value to assign is null and this property
        // accessor is for a value type, use a default value
        // instead
        //
        object newValue = value;
        if(newValue == null && PropertyType.IsValueType)
        {
            newValue = DefaultValue;  
        }
 
        //
        // Set the property value
        //
        this.mEmittedPropertyAccessor.Set(target, newValue);
    }
    else
    {
        throw new 
        PropertyAccessorException(string.Format("Property \"{0}\" does" + 
            " not have a set method.", mProperty));
    }
}

 
James
GeneralExtended for field accessorsmembersgheeren22 Jul '05 - 4:54 
James,
 
nice work. It was *almost* what i needed. I had the same use-case regarding public fields instead of properties. So I sat down and refactored a bit Smile | :) cheers, it refactored just fine (which compliments your style).
 
I factored out an (abstract) base class MemberAccessor, which has two descendants, FieldAccessor and PropertyAccessor, obviously.
 
The descendants sole task is to implement EmitSetter() and EmitGetter() (which are abstract methods on the baseclass.
 
I even sat down and refactored the tests. All tests relevant to both fields and methods have moved into a baseclass MemberAccessorTest, and the derived TestFixtures PropertyAccessorTest/FieldAccesorTest extend this with specific tests (e.g. there is no such thing as a WriteOnly field, and no such thing as a 'const' property).
 
Obviously there has been major find/replace Property->Member to keep the naming consistent with the purposes (e.g. IMemberAccessor instead of IPropertyAccessor).
 
The icing on the cake may be a factory method MemberAccessor.Make(...) which will instantiate either a PropertyAccessor or FieldAccessor by reflection.
 
If you are interested i will send/upload (?) the extended project 'FastDynamicMemberAccessor.proj'.
 
PS1. performance might have gone up by a chance to EmitAssembly that creates a 'sealed' class (gives compiler a huge optimization clue)
PS2. yes I use public fields for simple XmlSerializer-able classes Smile | :)
PS3. Needless to say, SampleApp runs without modification
PS4. The sharing of 36 test cases across the field/property variants has been achieved by implementing PropertyAccessorTestObject/FieldAccessorTestObject with a shared interface IMemberAccessorTestObject Smile | :) that interface is *only* used for test asserts, not for member access, of course
GeneralRe: Extended for field accessorsmemberMarc Brooks15 May '06 - 8:24 
Did you publish your changes somewhere?
GeneralRe: Extended for field accessorsmembersgheeren16 May '06 - 5:37 
not yet. i may have them lying somewhere... i'll have to delve deep to find them now Smile | :)
AnswerRe: Extended for field accessors [modified]membersgheeren26 May '06 - 4:31 
peeps I just uplinked my patches as I found a backup Source repository Smile | :)
 
The server may not always be online, good luck:
http://downloads.sehe.nl/FastDynamicMemberAccessor.zip
 

-- modified at 17:06 Saturday 18th August, 2007
see http://weblogs.asp.net/okloeten/archive/2006/06/21/Fast-Dynamic_2C00_-Generic-and-Simple-Property-Access-with-C_2300_.aspx
GeneralRe: Extended for field accessorsmembersgheeren16 May '06 - 5:50 
From quickly glancing thourgh the other comments (espec. performance optimization) if I remember well I have included most if not all of those fixes in my extended version as well (it's just what I do when i refactor, I did'nt bother with the benchmarks so I didn't notice any potential speedups)
 
Seth
Generalcongratulations!! and a questionmemberrurum22 Jun '05 - 12:10 
Your code is very good, congratulations!
I have a question:
I have a code where I use the "PropertyInfo.Invoke", (that is to say a reflection methods call)a lot of times.
 
So, I need to know if is possible adjust your code for my requirements and upgrade my response times or your code only run with property calls? (type.InvokeMember) ?
 
Where I will change your code for this goal ?
 
Thaks for your help.
 
rurum - x
GeneralRe: congratulations!! and a questionmemberJames Nies15 Jul '05 - 19:34 
It would as long as the methods you are invoking exhibit enough commonality to produce an interface that describes them. Such an interface might look something like the following...
 
public interface IMyMethodInvoker
{
//
// Common method (where target is an instance of a type you were previously
// calling MethodInfo.Invoke for)
//
void MyProcessingMethod(object target, object commonParam1, object commonParam2);
}
 
You would then create a class MyMethodInvoker that would implement the above interface. The MyMethodInvoker would emit a private Type that also implements the interface, but with IL that is specific to each target type.
 
Hope that helps...

 
James
GeneralNicememberreinux4 Apr '05 - 10:42 
I'd never have thought of it. Thanks!
GeneralA few optimizationsmemberKris Vandermotten29 Mar '05 - 8:12 
A very good example of using Reflection.Emit to avoid repeated reflection.
 
I have a few suggestions:
 
First of all, you're initializing mTypeHash for every PropertyAccessor you create. This is not necessary, and I would suggest to declare this field as static:
 
private static Hashtable mTypeHash;
 
Initialization would then have to happen in a static constructor:
 
static PropertyAccessor()
{
  mTypeHash=new Hashtable();
  mTypeHash[typeof(sbyte)]=OpCodes.Ldind_I1;
  // etc.
}

 
Secondly, why not do the call to Init() in the constructor? That would avoid the tests for null values in the Get and Set methods.
 
Is the test for CanRead in Get() (and the test for CanWrite in Set()) actually necessary? I haven't tested it, but my understanding is that the emited code would throw a MissingMethodException anyway?
 
Another possible optimization would be to cache the generated EmittedPropertyAccessor in a static Hashtable, to avoid regeneration when a new PropertyAccessor is created with the same parameters. Whether this is actually an optimization obviously depends on the nature of the calling code.
 
And if you allow me to make a final suggestion, even if this is a matter of style rather than optimization: I would personally use a property, named Value for example, instead of the Get and Set methods.
 
Hope this helps and keep up the good work,
 
Kris Vandermotten.
GeneralRe: A few optimizationsmemberJames Nies29 Mar '05 - 12:47 
Thanks for all the great suggestions Kris. Smile | :) The mTypeHash definitely should be static.
 
Secondly, why not do the call to Init() in the constructor? That would avoid the tests for null values in the Get and Set methods.
 
I lazily performed the Reflection.Emit calls under the assumption that I may never attempt to access a given property. This will benefit me in my particular application of this code, since I'll be creating many ProperyAccessors that may never get used. I suppose this all depends on what the calling code will be doing.
 
Another possible optimization would be to cache the generated EmittedPropertyAccessor in a static Hashtable, to avoid regeneration when a new PropertyAccessor is created with the same parameters. Whether this is actually an optimization obviously depends on the nature of the calling code.
 
I plan on using the PropertyAccessor class in a manner similar to what you suggest. I'll be caching classes in a Hashtable that contain all the PropertyAccessors for a given Type.
 
And if you allow me to make a final suggestion, even if this is a matter of style rather than optimization: I would personally use a property, named Value for example, instead of the Get and Set methods.
 
I can't see Value being a property... there needs to be some way to send in the target object.
 
James
 

GeneralRe: A few optimizationsmemberSteve Hansen23 May '06 - 23:03 
You could use an indexer instead of Value property that way you can do:
object value = property[myObject];
property[myObject] = "newvalue";
instead of
object value = property.Get(myObject);
property.Set(myObject, "newvalue");
Questionwhat license?memberRoger J29 Mar '05 - 0:04 
Hi,
We are currently evaluating your emitted property accessors in our opensource ORMapper framework:
http://www.npersist.com/[^]
 
We are building an object query engine right now to make it possible to run sql like queries against in mem lists of objects (to make it possible for users to run queries on already loaded objects w/o hitting the DB).
and your solution is perfect when evaluating property values of the objects.
 

so, what kind of license is this released under?
the ormapper project is LGPL , would it be ok to include your code in such project?
 
//Roger
 


AnswerRe: what license?memberJames Nies31 Mar '05 - 18:41 
Sorry, I hadn't really considered licensing when I posted this. Yes, feel free to use this in any project, open source or commercial. All I ask is that you please leave the original header with author information in the source. I'll update the project file with clarified licensing information sometime in the future.
 
By the way, NPersist seems like a very exciting project! I've heard of it before, but until now had not taken the time to look over the site. I'll definitely have to try it out sometime... perhaps even contribute if I can ever find the time.
 
James
Generalvs Reflectionmembersmoot425 Mar '05 - 16:15 
Very nice, this is really cool. A few comments though:
 
The Reflection tests are really "cheating" IMO. Any decent Reflection helper is going to cache MethodInfo, so putting that in the inner loop doesn't seem fair.
 
Even after correcting that, (and adding a HighPerformanceTimer), this is still 4 to 20 times faster than Reflection, so that's pretty cool. It's not until you get down to around 10,000 iterations that Reflection gains parity again.
 
So naturally I wondered how it would do if you didn't include instantiation and initialization in the benchmarks. So I moved the instantiation outside of the timer (for both PropertyAccessor and Reflection tests), and called the test invocation once before I started the timer to make sure everything was initialized (again, for both, tho' I don't think it matters for Reflection). Then I added some percentages to the tests. Now the number of iterations have little effect. The PropertyAccessor invocations are consistently 10 to 20 times faster.
 
That can lead to some pretty impressive gains if you do a lot of reflection I think.
GeneralRe: vs ReflectionmemberJames Nies28 Mar '05 - 12:00 
Thanks for the additional benchmarking Smoot! Smile | :)
 
James
Generalrules enginememberMarc Sommer24 Mar '05 - 19:34 
Hello James,
 
just noticed you are working on a rule engine. Is this a closed, non-public, business project or is there are change to see what you are doing. I am very much interessted in it and would love to see how you have done it. What kind of rule engine are you writing?
 
Best regrads,
 
Marc
GeneralRe: rules enginememberJames Nies25 Mar '05 - 9:06 
Hi Marc,
 
Unfortunatly the rules engine I am working on is part of a non-public, business project. I'd love to share more about it, but honestly its still in its infancy. The source for this article comes from my initial prototyping efforts.
 
James
GeneralSmall bugmemberDale Thompson24 Mar '05 - 10:07 
Very cool article. Just wanted to let you know that I think there is a bug in the mTypeHash setup.
 
The line:
mTypeHash[typeof(ulong)]=OpCodes.Ldind_I8;
 
should probably be:
mTypeHash[typeof(ulong)]=OpCodes.Ldind_U8;
 
Dale Thompson
GeneralRe: Small bugmemberJames Nies25 Mar '05 - 8:52 
I was going to go put this change through, but then I noticed that the OpCodes namespace does not have a Ldind_U8 operation defined. As mentioned in the source code, I just grabbed this section of code from someone else's work... I scoured the internet briefly for information on the ulong type and the Ldind_I8 op and didn't find the answer I was looking for. However, I did come across a couple other pieces of source that are also using the Ldind_I8 op.
 
Does anyone know why a Ldind_U8 operation does not exist?
GeneralRe: Small bugmemberDale Thompson28 Mar '05 - 3:00 
Oops - there is no Ldind_U8. The closest would be to cast to Ldind_I8.
 
Well, with 2 ^ 63 positive values, I'm sure this is close enough! Big Grin | :-D
 
Dale Thompson
GeneralVery cool!memberMarc Brooks23 Mar '05 - 5:23 
The only speed up I can see now is to not have to box and unbox the parameters and return value from the Get and Set. With 2.0 and a parameterized-type interface that should be possible. Then the only place you would have to worry about types is if you want to handle auto-coercion.
 
Nice!
GeneralTime tests seem to be flawed...membercjbreisch23 Mar '05 - 2:04 
Shouldn't the line
 
PropertyAccessor propertyAccessor =
new PropertyAccessor(typeof(PropertyAccessorTestObject), "Int");
 
be in the for loop? After all, that's where you're setting up what property value you're going to be retrieving. In practice, I'm not going to be hitting the same property value over and over, but conceivably many different property values over and over. Should be I expected to have accessor's instantiated for each and every one all the time? That's what the timing code seems to imply...
 
I gather I'm missing something completely obvious.
 
Chris J. Breisch, MCSD, MCDBA, MCSA
GeneralRe: Time tests seem to be flawed...memberleppie23 Mar '05 - 3:20 
cjbreisch wrote:
In practice, I'm not going to be hitting the same property value over and over, but conceivably many different property values over and over.
 
And that's when you should be using reflection Smile | :)
 
xacc-ide 0.0.15 now with C#, MSIL, C, XML, ASP.NET, Nemerle, MyXaml and HLSL coloring - Screenshots
GeneralRe: Time tests seem to be flawed...memberJames Nies23 Mar '05 - 4:09 
If you're not going to be looking at the same property for a given type inside your processing loop, then yes, you will be far better off using reflection. It would be extremely slow to have to create a PropertyAccessor during each iteration.
 
However, if you'll be looking at the same Property (different instance of course) inside your loop and you can create a PropertyAccessor before going in, this should offer a drastic increase in performance.
 
As for the time tests, they are probably pretty skewed because they are looking at the same instance.
GeneralRe: Time tests seem to be flawed...membersgheeren16 May '06 - 5:55 
The obvious here would be that these are separate use cases. They need separate benchmarks. Go for it, and maybe define an 'average' total benchmark result as well!
 
(PS. I use them with fixed property names all the time, so the test match at leat my use case)
GeneralCool :)memberleppie23 Mar '05 - 1:45 
This is good work Smile | :) Although your usage of Reflection is using the slowest way of all, your method still has a HUGE advantage Smile | :) Also using more iterations will give you much better comparitive values due to the low resolution of DateTime (>10ms). Here's my results using the following pattern instead.
 
Pattern:
start = DateTime.Now;
Type type = testObject.GetType();
PropertyInfo pi = type.GetProperty("String");
 
for(int i = 0; i < TEST_ITERATIONS; i++)
{
	test = (string)pi.GetValue(testObject, null);
}
end = DateTime.Now;
Results:
10000000 property gets on integer...
Direct access ms:                               62.5
PropertyAccessor (Reflection.Emit) ms:          484.375
Reflection ms:                                  6515.625
 
10000000 property sets on integer...
Direct access ms:                               78.125
PropertyAccessor (Reflection.Emit) ms:          484.375
Reflection ms:                                  11046.875
 
10000000 property gets on string...
Direct access ms:                               62.5
PropertyAccessor (Reflection.Emit) ms:          359.375
Reflection ms:                                  6000
 
10000000 property sets on string...
Direct access ms:                               109.375
PropertyAccessor (Reflection.Emit) ms:          421.875
Reflection ms:                                  9609.375

 
xacc-ide 0.0.15 now with C#, MSIL, C, XML, ASP.NET, Nemerle, MyXaml and HLSL coloring - Screenshots

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 23 Mar 2005
Article Copyright 2005 by James Nies
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid