Skip to content

Instantly share code, notes, and snippets.

@codeimpossible
Created October 28, 2014 02:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save codeimpossible/cee2a0b0679f6c82ce04 to your computer and use it in GitHub Desktop.
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
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 );
}
}
}
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