Last active
August 29, 2015 14:00
-
-
Save azyobuzin/11081382 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
using System; | |
using System.Collections.Concurrent; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Linq.Expressions; | |
using System.Reflection; | |
using System.Runtime.CompilerServices; | |
using System.Threading.Tasks; | |
using Livet; | |
namespace Azyotter.Models | |
{ | |
public class ModelBase : NotificationObject | |
{ | |
private static readonly ConcurrentDictionary<Type, ConcurrentDictionary<string, Tuple<Func<object, object>, Action<object, object>>>> | |
propCache = new ConcurrentDictionary<Type, ConcurrentDictionary<string, Tuple<Func<object, object>, Action<object, object>>>>(); | |
protected void Set<T>(T value, [CallerMemberName] string propName = null) | |
{ | |
var thisType = this.GetType(); | |
var cacheDic = propCache.GetOrAdd(thisType, new ConcurrentDictionary<string, Tuple<Func<object, object>, Action<object, object>>>()); | |
Tuple<Func<object, object>, Action<object, object>> t; | |
if (cacheDic.TryGetValue(propName, out t)) | |
{ | |
var old = (T)t.Item1(this); | |
if (!EqualityComparer<T>.Default.Equals(old, value)) | |
{ | |
t.Item2(this, value); | |
this.RaisePropertyChanged(propName); | |
} | |
} | |
else | |
{ | |
var tType = typeof(T); | |
FieldInfo field = this.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic) | |
.First(f => f.FieldType.IsAssignableFrom(tType) && | |
(f.Name.Equals(propName, StringComparison.InvariantCultureIgnoreCase) | |
|| f.Name.Equals("_" + propName, StringComparison.InvariantCultureIgnoreCase))); | |
var old = (T)field.GetValue(this); | |
if (!EqualityComparer<T>.Default.Equals(old, value)) | |
{ | |
field.SetValue(this, value); | |
this.RaisePropertyChanged(propName); | |
} | |
TaskEx.Run(() => | |
{ | |
var objType = typeof(object); | |
var sourcePrm = Expression.Parameter(objType, "source"); | |
var getFunc = Expression.Lambda<Func<object, object>>( | |
Expression.Convert( | |
Expression.Field( | |
Expression.Convert(sourcePrm, thisType), | |
field | |
), | |
objType | |
), | |
sourcePrm | |
).Compile(); | |
var targetPrm = Expression.Parameter(objType, "target"); | |
var valuePrm = Expression.Parameter(objType, "value"); | |
var setAction = Expression.Lambda<Action<object, object>>( | |
Expression.Call( | |
typeof(ModelBase).GetMethod("Assign", BindingFlags.NonPublic | BindingFlags.Static) | |
.MakeGenericMethod(tType), | |
Expression.Field( | |
Expression.Convert(targetPrm, thisType), | |
field | |
), | |
Expression.Convert(valuePrm, tType) | |
), | |
targetPrm, | |
valuePrm | |
).Compile(); | |
cacheDic.TryAdd(propName, Tuple.Create(getFunc, setAction)); | |
}); | |
} | |
} | |
private static void Assign<T>(ref T left, T right) | |
{ | |
left = right; | |
} | |
protected override void RaisePropertyChanged([CallerMemberName] string propertyName = "") | |
{ | |
base.RaisePropertyChanged(propertyName); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment