Created
September 30, 2014 21:18
-
-
Save Simie/ab4c23fbc91ea72909da to your computer and use it in GitHub Desktop.
Bolt Expression
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
using UnityEngine; | |
using System; | |
using System.Collections.Generic; | |
using System.Linq.Expressions; | |
namespace ExpressionTest | |
{ | |
public static class PathExtractor<T> | |
{ | |
/// <summary> | |
/// Extract a path string from a lambda expression | |
/// </summary> | |
/// <param name="tree">Tree.</param> | |
/// <typeparam name="TProperty">The 1st type parameter.</typeparam> | |
public static string Extract<TProperty>(Expression<Func<T, TProperty>> tree) | |
{ | |
var propString = ""; | |
var lambda = (LambdaExpression)tree; | |
Extract(lambda.Body, ref propString); | |
return propString; | |
} | |
private static void Extract(Expression expr, ref string str) | |
{ | |
// The root of the expression (whatever the argument name is) is not required | |
if (expr is ParameterExpression) { | |
return; | |
} else if (expr is MethodCallExpression) { | |
// If it's a method call, it's probably an index accessor | |
var method = (MethodCallExpression) expr; | |
// Ensure that it is actually an indexer | |
if(!method.Method.Name.Contains("get_Item")) | |
throw new InvalidOperationException(); | |
// Extract whatever is before this in the expression | |
if (method.Object != null) | |
Extract(method.Object, ref str); | |
// Just add a [] | |
str += "[]"; | |
// TODO: Don't [] if at the end of the expression? | |
} else if (expr is MemberExpression) { | |
// Simple member accessor, just add the member name | |
var member = (MemberExpression) expr; | |
if (member.Expression != null) | |
Extract(member.Expression, ref str); | |
str += "." + member.Member.Name; | |
} else { | |
throw new NotImplementedException("Expression type is unhandled"); | |
} | |
} | |
} | |
public class NestLevel1 | |
{ | |
public int Value; | |
public IList<NestLevel2> Nest { get; private set; } | |
} | |
public class NestLevel2 | |
{ | |
public bool Value; | |
} | |
public class SomeStateObject | |
{ | |
public IList<NestLevel1> Embeded { get; private set; } | |
// TODO: Use another data stucture, as this doesn't allow multiple registrations for the same member path | |
private Dictionary<string, Delegate> _callbackDictionary = new Dictionary<string, Delegate>(); | |
public void RegisterCallback<TEvent>(Expression<Func<SomeStateObject, TEvent>> expr, Action<SomeStateObject, TEvent> onChanged) | |
{ | |
// Extract the member path | |
var path = PathExtractor<SomeStateObject>.Extract(expr); | |
// Add the event to the callback dictionary using the member path as a key | |
_callbackDictionary[path] = onChanged; | |
Debug.Log("Registered callback for " + path); | |
} | |
public void TriggerCallback<TEvent>(Expression<Func<SomeStateObject, TEvent>> expr, TEvent newValue) | |
{ | |
// Extract the path | |
var path = PathExtractor<SomeStateObject>.Extract(expr); | |
// Cast the delegate to the expected type and invoke with the changed object and new value | |
((Action<SomeStateObject, TEvent>) _callbackDictionary[path]).Invoke(this, newValue); | |
} | |
} | |
} |
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
using UnityEngine; | |
using System.Collections; | |
using ExpressionTest; | |
public class TestBehaviour : MonoBehaviour { | |
string result; | |
void Awake() { | |
Application.RegisterLogCallback(LogCallback); | |
} | |
void Start () { | |
var someStateObject = new SomeStateObject(); | |
someStateObject.RegisterCallback(c => c.Embeded[0].Nest[0].Value, OnChanged); | |
someStateObject.TriggerCallback(c => c.Embeded[0].Nest[0].Value, true); | |
someStateObject.TriggerCallback(c => c.Embeded[0].Nest[0].Value, false); | |
} | |
private void OnChanged(SomeStateObject testClass, bool newValue) | |
{ | |
Debug.Log("OnChanged: " + newValue); | |
} | |
void OnGUI() { | |
GUILayout.Label(result); | |
} | |
void LogCallback(string info, string stack, LogType type) | |
{ | |
result += string.Format("{0}: {1}\n", type, info); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment