Skip to content

Instantly share code, notes, and snippets.

@azyobuzin
Last active August 29, 2015 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save azyobuzin/11081382 to your computer and use it in GitHub Desktop.
Save azyobuzin/11081382 to your computer and use it in GitHub Desktop.
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