Skip to content

Instantly share code, notes, and snippets.

@werwolfby
Created December 24, 2017 09:50
Show Gist options
  • Save werwolfby/b51ba864489482440d1813f66e04a00a to your computer and use it in GitHub Desktop.
Save werwolfby/b51ba864489482440d1813f66e04a00a to your computer and use it in GitHub Desktop.
/*******************************************************
*
* Created by: Alexander Puzynia aka WerWolf
* Created: 17.10.2010 23:36
*
* File: MemberAccessorHelper.cs
* Remarks:
*
* History:
* 17.10.2010 23:36 - Create Wireframe
* 17.10.2010 23:50 - Add special [MemberAccessorHelper] static class with factory method [Create].
* 18.10.2010 00:05 - Add implicit cast operator from [Expression<Func<TMember>>].
* 23.10.2010 21:09 - Rename [MemberAccessorHelper] classes to [MemberAccessor].
* Add support of [.Net Framework 3.5] over FW35 define directive.
* 23.10.2010 21:45 - Add support access to [static] members.
*
*******************************************************/
using System;
using System.Linq.Expressions;
using System.Reflection;
#if FW35
using System.Reflection.Emit;
#endif
namespace Test.MemberAccessor
{
public abstract class MemberAccessor<TMember>
{
protected readonly Func<TMember> getter;
protected readonly Action<TMember> setter;
protected MemberAccessor( Func<TMember> getter, Action<TMember> setter )
{
this.getter = getter;
this.setter = setter;
}
public TMember Value
{
get { return this.getter(); }
set { this.setter( value ); }
}
public static implicit operator MemberAccessor<TMember>(Expression<Func<TMember>> expression)
{
return MemberAccessor.Create( expression );
}
}
internal class MemberAccessor<TContainer, TMember> : MemberAccessor<TMember>
where TContainer : class
{
#if FW35
private class Box
{
public TContainer container;
}
#endif
public MemberAccessor(TContainer container, MemberExpression memberAccess)
: base(CreateGetter(memberAccess), CreateSetter(container, memberAccess))
{
}
private static Func<TMember> CreateGetter( MemberExpression memberAccess )
{
var getterExpression = Expression.Lambda<Func<TMember>>( memberAccess );
return getterExpression.Compile();
}
private static Action<TMember> CreateSetter( TContainer container, MemberExpression memberAccess )
{
#if FW4
var parameterValueExpression = Expression.Parameter( typeof(TMember), "v" );
var setterExpression = Expression.Lambda<Action<TMember>>(
Expression.Assign(
memberAccess,
parameterValueExpression ),
parameterValueExpression );
return setterExpression.Compile();
#elif FW35
var box = container != null
? new Box { container = container }
: null;
var parameterTypes = container != null
? new[] { typeof(Box), typeof(TMember) }
: new[] { typeof(TMember) };
var dynamicMethod = new DynamicMethod( "setter", typeof(void), parameterTypes, true );
var il = dynamicMethod.GetILGenerator();
// Not static member accessor
if (container != null)
{
il.Emit( OpCodes.Ldarg_0 );
il.Emit( OpCodes.Ldfld, StaticReflection<Box>.GetField( t => t.container ) );
il.Emit( OpCodes.Ldarg_1 );
}
else
{
il.Emit( OpCodes.Ldarg_0 );
}
var member = memberAccess.Member;
switch (member.MemberType)
{
case MemberTypes.Field:
il.Emit( container != null ? OpCodes.Stfld : OpCodes.Stsfld, ((FieldInfo)member) );
break;
case MemberTypes.Property:
il.EmitCall( OpCodes.Callvirt, (((PropertyInfo)member).GetSetMethod( true )), null );
break;
}
il.Emit( OpCodes.Ret );
return (Action<TMember>)(box != null
? dynamicMethod.CreateDelegate( typeof(Action<TMember>), box )
: dynamicMethod.CreateDelegate( typeof(Action<TMember>) ));
#else
#error Not supported target framework
#endif
}
}
public static class MemberAccessor
{
public static MemberAccessor<TMember> Create<TMember>(Expression<Func<TMember>> accessor)
{
var memberExpression = StaticReflection.GetMemberExpression( accessor );
// Static member accessor
if (memberExpression.Expression == null)
return new MemberAccessor<object, TMember>( null, memberExpression );
// Not static member accessor
if (memberExpression.Expression.NodeType != ExpressionType.Constant)
throw new Exception( "Expression has wrong format, exprected: () => this.Member" );
var constantExpression = (ConstantExpression)memberExpression.Expression;
var container = constantExpression.Value;
var memberAccessorType = typeof(MemberAccessor<,>).MakeGenericType( constantExpression.Type, typeof(TMember) );
return (MemberAccessor<TMember>)Activator.CreateInstance( memberAccessorType, container, memberExpression );
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment