Skip to content

Instantly share code, notes, and snippets.

@JakeGinnivan
Last active August 29, 2015 14:02
Show Gist options
  • Select an option

  • Save JakeGinnivan/a8dd02203cb871a9c16a to your computer and use it in GitHub Desktop.

Select an option

Save JakeGinnivan/a8dd02203cb871a9c16a to your computer and use it in GitHub Desktop.
public sealed class ArrayEqualityComparer<T> : IEqualityComparer<T[]>
{
// You could make this a per-instance field with a constructor parameter
private static readonly EqualityComparer<T> ElementComparer
= EqualityComparer<T>.Default;
public bool Equals(T[] first, T[] second)
{
if (first == second)
{
return true;
}
if (first == null || second == null)
{
return false;
}
if (first.Length != second.Length)
{
return false;
}
return !first.Where((t, i) => !ElementComparer.Equals(t, second[i])).Any();
}
public int GetHashCode(T[] array)
{
unchecked
{
if (array == null)
{
return 0;
}
return array.Aggregate(17, (current, element) => current * 31 + ElementComparer.GetHashCode(element));
}
}
}
public static class ObservableExtensions
{
public static string GetPropertyName<TSource, TProp>(
this TSource source,
Expression<Func<TSource, TProp>> propertyExpression)
{
var memberExpression = CompiledExpressionHelper<TSource, TProp>.GetMemberExpression(propertyExpression);
return memberExpression.Member.Name;
}
public static IObservable<TProp> ObservePropertyChanged<TSource, TProp>(
this TSource source,
Expression<Func<TSource, TProp>> propertyExpression,
bool observeInitialValue = false) where TSource : INotifyPropertyChanged
{
return Observable.Create<TProp>(
o =>
{
var propertyName = GetPropertyName(source, propertyExpression);
var selector = CompiledExpressionHelper<TSource, TProp>.GetFunc(propertyExpression);
var observable =
from evt in
Observable.FromEvent<PropertyChangedEventHandler, PropertyChangedEventArgs>(
h => (s, e) => h(e),
h => source.PropertyChanged += h,
h => source.PropertyChanged -= h)
where evt.PropertyName == propertyName
select selector(source);
observable = observeInitialValue ? observable.StartWith(selector(source)) : observable;
return observable.Subscribe(o);
});
}
public static IObservable<TProp> ObservePropertyBeingChanged<TSource, TProp>(
this TSource source,
Expression<Func<TSource, TProp>> propertyExpression,
bool observeInitialValue = false) where TSource : IPropertyBeingUpdated
{
return Observable.Create<TProp>(
o =>
{
var propertyName = GetPropertyName(source, propertyExpression);
var selector = CompiledExpressionHelper<TSource, TProp>.GetFunc(propertyExpression);
var observable =
from evt in
Observable.FromEvent<string>(
h => source.PropertyBeingUpdated += h,
h => source.PropertyBeingUpdated -= h)
where evt == propertyName
select selector(source);
observable = observeInitialValue ? observable.StartWith(selector(source)) : observable;
return observable.Subscribe(o);
});
}
public static IObservable<Unit> ObservePropertiesBeingChanged<TSource>(
this TSource source,
params Expression<Func<TSource, object>>[] propertyExpressions) where TSource : IPropertyBeingUpdated
{
var selectors = propertyExpressions.Select(CompiledExpressionHelper<TSource, object>.GetFunc).ToArray();
return propertyExpressions
.Select(expr => ObservePropertyBeingChanged(source, expr).Select(_ => Unit.Default))
.Merge()
.Select(_ => selectors.Select(s => s(source)).ToArray())
.DistinctUntilChanged(new ArrayEqualityComparer<object>())
.Select(_ => Unit.Default);
}
public static IObservable<Unit> ObservePropertiesChanged<TSource>(
this TSource source,
params Expression<Func<TSource, object>>[] propertyExpressions) where TSource : INotifyPropertyChanged
{
var selectors = propertyExpressions.Select(CompiledExpressionHelper<TSource, object>.GetFunc).ToArray();
return propertyExpressions
.Select(expr => ObservePropertyChanged(source, expr).Select(_ => Unit.Default))
.Merge()
.Select(_ => selectors.Select(s => s(source)).ToArray())
.DistinctUntilChanged(new ArrayEqualityComparer<object>())
.Select(_ => Unit.Default);
}
private static class CompiledExpressionHelper<TSource, TProp>
{
private static readonly Dictionary<string, Func<TSource, TProp>> Funcs =
new Dictionary<string, Func<TSource, TProp>>();
public static Func<TSource, TProp> GetFunc(Expression<Func<TSource, TProp>> propertyExpression)
{
var memberExpression = GetMemberExpression(propertyExpression);
var propertyName = memberExpression.Member.Name;
var key = typeof(TSource).FullName + "." + propertyName;
Func<TSource, TProp> func;
if (!Funcs.TryGetValue(key, out func))
{
Funcs[key] = propertyExpression.Compile();
}
return Funcs[key];
}
public static MemberExpression GetMemberExpression(Expression<Func<TSource, TProp>> propertyExpression)
{
MemberExpression memberExpression;
var unaryExpr = propertyExpression.Body as UnaryExpression;
if (unaryExpr != null && unaryExpr.NodeType == ExpressionType.Convert)
{
memberExpression = (MemberExpression)unaryExpr.Operand;
}
else
{
memberExpression = (MemberExpression)propertyExpression.Body;
}
return memberExpression;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment