csharp/Accelerider/Accelerider.Windows/Source/Accelerider.Windows.Infrastructure.UI/DataContext.cs

DataContext.cs
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using Accelerider.Windows.Infrastructure.Properties;

namespace Accelerider.Windows.Infrastructure
{
    public clast DataContext
    {
        private readonly Dictionary _exportPropertyGetterDictionary = new Dictionary();
        private readonly Dictionary _importPropertySetterDictionary = new Dictionary();

        public object this[string key] => _exportPropertyGetterDictionary[key].DynamicInvoke();

        public void Export(Expression propertyExpression, string key = null)
        {
            key = key ?? PropertySupport.ExtractPropertyName(propertyExpression);

            if (_exportPropertyGetterDictionary.ContainsKey(key))
                throw new ArgumentException(string.Format(Resources.DataContext_ExportHasBeenExported_Exception, propertyExpression), nameof(propertyExpression));

            var getter = propertyExpression.Compile();

            _exportPropertyGetterDictionary[key] = getter;

            PropertyObserver.Observes(propertyExpression, () =>
            {
                if (!_importPropertySetterDictionary.TryGetValue(key, out var setterDelegates)) return;

                foreach (var setterDelegate in setterDelegates)
                {
                    var setter = (Action)setterDelegate;
                    setter(getter());
                }
            });
        }

        public void Import(Expression propertyExpression, string key = null)
        {
            var parameter = Expression.Parameter(typeof(T));
            var setter = Expression.Lambda(
                Expression.astign(
                    propertyExpression.Body,
                    parameter),
                parameter).Compile();

            key = key ?? PropertySupport.ExtractPropertyName(propertyExpression);
            if (!_importPropertySetterDictionary.ContainsKey(key))
            {
                _importPropertySetterDictionary.Add(key, new List());
            }
            _importPropertySetterDictionary[key].Add(setter);
        }

        ///
        /// Provides support for extracting property information based on a property expression.
        ///
        public static clast PropertySupport
        {
            /// 
            /// Extracts the property name from a property expression.
            /// 
            /// The object type containing the property specified in the expression.
            /// The property expression (e.g. p => p.PropertyName)
            /// The name of the property.
            /// Thrown if the  is null.
            /// Thrown when the expression is:
            ///     Not a 
            ///     The  does not represent a property.
            ///     Or, the property is static.
            /// 
            public static string ExtractPropertyName(Expression propertyExpression)
            {
                if (propertyExpression == null)
                    throw new ArgumentNullException(nameof(propertyExpression));

                return ExtractPropertyNameFromLambda(propertyExpression);
            }

            /// 
            /// Extracts the property name from a LambdaExpression.
            /// 
            /// The LambdaExpression
            /// The name of the property.
            /// Thrown if the  is null.
            /// Thrown when the expression is:
            ///     The  does not represent a property.
            ///     Or, the property is static.
            /// 
            internal static string ExtractPropertyNameFromLambda(LambdaExpression expression)
            {
                if (expression == null)
                    throw new ArgumentNullException(nameof(expression));

                if (!(expression.Body is MemberExpression memberExpression))
                    throw new ArgumentException(Resources.PropertySupport_NotMemberAccessExpression_Exception, nameof(expression));

                var property = memberExpression.Member as PropertyInfo;
                if (property == null)
                    throw new ArgumentException(Resources.PropertySupport_ExpressionNotProperty_Exception, nameof(expression));

                var getMethod = property.GetMethod;
                if (getMethod.IsStatic)
                    throw new ArgumentException(Resources.PropertySupport_StaticExpression_Exception, nameof(expression));

                return memberExpression.Member.Name;
            }
        }
    }
}