namespace Namespace1
{
public static class PropertyAccessTest
{
public static void Run()
{
var nTimes = 2500000;
var value = "Hello World";
var myTestType
= new MyObject
(); DateTime start, end;
var property
= typeof(MyObject
).GetProperty("MyProperty");
Stopwatch sw
= new Stopwatch
(); sw.Start();
for (var i = 0; i < nTimes; i++)
{
property.SetValue(myTestType, value, null);
}
sw.Stop();
Console.WriteLine("Straight reflection: PropertyInfo.SetValue(): {0} ms", sw.ElapsedMilliseconds);
dynamic myTestType2
= new MyObject
(); sw.Reset();
sw.Start();
for (int i = 0; i < nTimes; i++)
{
myTestType2.MyProperty = value;
}
sw.Stop();
Console.WriteLine("System.Dynamic: dynamic.MyProperty = value: {0} ms", sw.ElapsedMilliseconds);
var myObject3
= new MyObject
(); sw.Reset();
sw.Start();
for (int i = 0; i < nTimes; i++)
{
myObject3.MyProperty = value;
}
sw.Stop();
Console.WriteLine("Direct Code: MyObject.MyProperty = value: {0} ms", sw.ElapsedMilliseconds);
// Given an instance of an object, and a string
// identifying a property of the object:
FastProperty fastProp
= new FastProperty
( myObject3,
"MyProperty" );
// It's important to note that the instance of fastProp
// is both type- and member-specific, so it must be cached
// and keyed to both the type of the instance, and the
// property name, using some kind of caching scheme (which
// is merely an implementation detail):
sw.Reset();
sw.Start();
for (int i = 0; i < nTimes; i++)
{
fastProp.Set( myObject3, value );
}
sw.Stop();
Console.WriteLine("FastProperty: fastProp.Set(myObject3, value): {0} ms", sw.ElapsedMilliseconds);
}
public class MyObject
{
public string MyProperty { get; set; }
}
}
public class FastProperty
{
public PropertyInfo Property { get; set; }
public Func<object, object> GetDelegate;
public Action<object, object> SetDelegate;
public FastProperty( object instance, string property )
: this( instance.GetType().GetProperty( property ) )
{
}
public FastProperty(PropertyInfo property)
{
this.Property = property;
InitializeGet();
InitializeSet();
}
private void InitializeSet()
{
var instance
= Expression
.Parameter(typeof(object),
"instance"); var value = Expression
.Parameter(typeof(object),
"value");
// value as T is slightly faster than (T)value, so if it's not a value type, use that
UnaryExpression instanceCast = (!this.Property.DeclaringType.IsValueType) ? Expression.TypeAs(instance, this.Property.DeclaringType) : Expression.Convert(instance, this.Property.DeclaringType);
UnaryExpression valueCast = (!this.Property.PropertyType.IsValueType) ? Expression.TypeAs(value, this.Property.PropertyType) : Expression.Convert(value, this.Property.PropertyType);
this.SetDelegate = Expression
.Lambda<Action
<object,
object>>(Expression
.Call(instanceCast,
this.Property.GetSetMethod(), valueCast
),
new ParameterExpression
[] { instance,
value }).Compile(); }
private void InitializeGet()
{
var instance
= Expression
.Parameter(typeof(object),
"instance"); UnaryExpression instanceCast = (!this.Property.DeclaringType.IsValueType) ? Expression.TypeAs(instance, this.Property.DeclaringType) : Expression.Convert(instance, this.Property.DeclaringType);
this.GetDelegate = Expression
.Lambda<Func
<object,
object>>(Expression
.TypeAs(Expression
.Call(instanceCast,
this.Property.GetGetMethod()),
typeof(object)), instance
).Compile(); }
public object Get(object instance)
{
return this.GetDelegate(instance);
}
public void Set(object instance, object value)
{
this.SetDelegate(instance, value);
}
}
}