Created
December 24, 2017 09:50
-
-
Save werwolfby/b51ba864489482440d1813f66e04a00a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/******************************************************* | |
* | |
* 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