Created
October 28, 2014 02:52
-
-
Save codeimpossible/cee2a0b0679f6c82ce04 to your computer and use it in GitHub Desktop.
JamesBond - a quick and dirty lesson in reflection, invocation and generally mucking about with an objects private vars
This file contains hidden or 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
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Dynamic; | |
using System.Reflection; | |
using System.Linq.Expressions; | |
namespace MISix { | |
public class ReflectedResult<T> { | |
T result; | |
public ReflectedResult(T item) { | |
result = item; | |
} | |
public void ShouldEqual( object val ) { | |
if ( !result.Equals(val) ) { | |
throw new Exception(); | |
} | |
} | |
} | |
public enum Scope { | |
InstancePublic, | |
InstancePrivate, | |
MethodLocal, | |
StaticPublic, | |
StaticPrivate | |
} | |
public class Candidate { | |
public object Value { get; set; } | |
public string Name { get; set; } | |
public Scope Scope { get; set; } | |
} | |
public class JamesBond : DynamicObject { | |
object baseItem; | |
public static JamesBond SpiesOn<Reflector>( Reflector item ) { | |
return new JamesBond().Reflect<Reflector>( item ); | |
} | |
private JamesBond Reflect<Reflector>( Reflector item ) { | |
baseItem = item; | |
return this; | |
} | |
public IEnumerable<Candidate> Candidates( string name ) { | |
return null; | |
} | |
public ReflectedResult<object> Spy( Func<dynamic, object> bond ) { | |
var result = bond( (dynamic)this ) as object; | |
return new ReflectedResult<object>(result); | |
} | |
public JamesBond Meddle( Action<dynamic> meddle ) { | |
meddle( ( dynamic )this ); | |
return this; | |
} | |
public override bool TrySetMember( SetMemberBinder binder, object value ) { | |
var memberName = binder.Name; | |
var method = hasMethod( memberName ); | |
IfHasItems( method, () => method.First().Invoke( baseItem, value as object[] ?? new object[] { value } ) ); | |
var instance = hasField( memberName ); | |
IfHasItems( instance, () => instance.First().SetValue( baseItem, value ) ); | |
return true; | |
} | |
public override bool TryGetMember( GetMemberBinder binder, out object result ) { | |
var memberName = binder.Name; | |
result = null; | |
var method = hasMethod( memberName ); | |
result = IfHasItems( method, () => method.First().Invoke( baseItem, null ) ); | |
if( result == null ) { | |
var instance = hasField( memberName ); | |
result = IfHasItems( instance, () => instance.First().GetValue( baseItem ) ); | |
} | |
return result == null ? base.TryGetMember( binder, out result ) : true; | |
} | |
private object IfHasItems<Type>( IEnumerable<Type> list, Func<object> action ) { | |
return list != null && list.Count() > 0 ? action() : null; | |
} | |
private void IfHasItems<Type>( IEnumerable<Type> list, Action action ) { | |
if( list != null && list.Count() > 0) | |
action(); | |
} | |
private IEnumerable<LocalVariableInfo> hasLocal( string localName ) { | |
var methods = baseItem.GetType().GetMethods( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static ); | |
var locals = new List<LocalVariableInfo>(); | |
foreach( var method in methods ) { | |
var body = method.GetMethodBody(); | |
foreach( var local in body.LocalVariables ) { | |
} | |
} | |
return null; | |
} | |
private IEnumerable<MethodInfo> hasMethod( string methodName ) { | |
return baseItem.GetType().GetMethods( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static ).Where( m => m.Name == methodName ); | |
} | |
private IEnumerable<FieldInfo> hasField( string memberName ) { | |
return baseItem.GetType().GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static ).Where( m => m.Name == memberName ); | |
} | |
private IEnumerable<MemberInfo> hasClassMember( string memberName ) { | |
return baseItem.GetType().GetMembers( BindingFlags.Static ).Where( m => m.Name == memberName ); | |
} | |
} | |
} |
This file contains hidden or 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
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using MISix; | |
namespace DynamicReflection { | |
public class Test { | |
private bool hello = false; | |
public void Work(int num) { | |
hello = num > 0; | |
} | |
} | |
class Program { | |
static void Main( string[] args ) { | |
var start = DateTime.Now; | |
var t = new Test(); | |
var grey = JamesBond.SpiesOn( t ); | |
grey.Spy( i => i.hello ).ShouldEqual( false ); | |
t.Work( 10 ); | |
grey.Spy( i => i.hello ).ShouldEqual( true ); | |
grey.Meddle( i => i.Work = 0 ) | |
.Spy( i => i.hello ).ShouldEqual( false ); | |
Console.WriteLine( "Tests Passed!" ); | |
Console.WriteLine( String.Format( "Took {0}ms", DateTime.Now.Subtract( start ).TotalMilliseconds ) ); | |
Console.ReadLine(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment