Usage Scenarios

Implement interface properties

For example, you have a lot of property containing interfaces like:

    public interface IAnimal
    {
        string Name { get; set; }
        int Age { get; set; }
    }

And you want to get implementation for all of them storing values in dictionary like:

    public class PropertyContainer
    {
        private readonly Dictionary<String, Object> _data = new Dictionary<string, object>();
        public TValue GetValue<TValue>(String name)
        {
            object value = null;
            if (!_data.TryGetValue(name, out value))
            {
                return default(TValue);
            }
            return (TValue) value;
        }
        public void SetValue<TValue>(String name,TValue value)
        {
            _data[name] = (object) value;
        }
    }

Then, using Yappi, solution will look as follows:

public class InterfaceImplementation<TInterface>:DefaultImplementation<PropertyContainer>
    {
        public override Func<TBaseType, TResult> ImplementGetter<TBaseType, TDeclaringType, TConstructedType, TResult>(PropertyInfo property)
        {
            var name = property.Name;
            return (i) => i.GetValue<TResult>(name);
        }
        public override Action<TBaseType, TResult> ImplementSetter<TBaseType, TDeclaringType, TConstructedType, TResult>(PropertyInfo property)
        {
            var name = property.Name;
            return (i, v) => i.SetValue(name, v);
        }
 
        public static readonly Type Type = PropertyProxy.ConstructType<PropertyContainer, InterfaceImplementation<TInterface>>(new Type[] { typeof(TInterface) });
 
        public static Func<TInterface> New = Constructor.Compile<Func<TInterface>>(Type);
    }

And can be used for any interface type like:

var animal = InterfaceImplementation<IAnimal>.New();

As you see, it saves a lot of work.

Override property accessors

For example, lets look at INotifiyPropertyChanged implementation:

    public class Concept:INotifyPropertyChanged
    {
        //Hide constructor
        protected Concept(){}
        
        public static class Create<TConcept> where TConcept:Concept
        {
            //Construct derived Type calling PropertyProxy.ConstructType
            public static readonly Type Type = PropertyProxy.ConstructType<TConcept, Implementation<TConcept>>(new Type[0], true);
            //Create constructing delegate calling Constructor.Compile
            public static Func<TConcept> New = Constructor.Compile<Func<TConcept>>(Type);
        }
 
 
        public event PropertyChangedEventHandler PropertyChanged;
        
        protected void OnPropertyChanged(PropertyChangedEventArgs eventArgs)
        {
            var caller = PropertyChanged;
            if(caller!=null)
            {
                caller(this, eventArgs);
            }
        }
 
        //define implementation
        public class Implementation<TConcept> : DefaultImplementation<TConcept> where TConcept:Concept
        {
            public override Func<TBaseType, TResult> OverrideGetter<TBaseType, TDeclaringType, TConstructedType, TResult>(PropertyInfo property)
            {
                return PropertyImplementation<TBaseType, TDeclaringType>.GetGetter<TResult>(property.Name);
            }
            /// <summary>
            /// Overriding property setter implementation.
            /// </summary>
            /// <typeparam name="TBaseType">Base type for implementation. TBaseType must be TConcept, and inherits all its constraints. Also TBaseType is TDeclaringType.</typeparam>
            /// <typeparam name="TDeclaringType">Type, declaring property.</typeparam>
            /// <typeparam name="TConstructedType">Constructed type. TConstructedType is TDeclaringType and TBaseType.</typeparam>
            /// <typeparam name="TResult">Type of property.</typeparam>
            /// <param name="property">PropertyInfo of property.</param>
            /// <returns>Delegate, corresponding to property setter implementation.</returns>
            public override Action<TBaseType, TResult> OverrideSetter<TBaseType, TDeclaringType, TConstructedType, TResult>(PropertyInfo property)
            {
                //This code called once for each declared property on derived type's initialization.
                //EventArgs instance is shared between all events for each concrete property.
                var eventArgs = new PropertyChangedEventArgs(property.Name);
                //get delegates for base calls.
                Action<TBaseType, TResult> setter = PropertyImplementation<TBaseType, TDeclaringType>.GetSetter<TResult>(property.Name);
                Func<TBaseType, TResult> getter = PropertyImplementation<TBaseType, TDeclaringType>.GetGetter<TResult>(property.Name);
 
                var comparer = EqualityComparer<TResult>.Default;
 
                return (pthis, value) =>
                {//This code executes each time property setter is called.
                    if (comparer.Equals(value, getter(pthis))) return;
                    //base. call
                    setter(pthis, value);
                    //Directly accessing Concept's protected method.
                    pthis.OnPropertyChanged(eventArgs);
                };
            }
        }
    }

This implementation, declared once in base class allows us to declare properties in derived class using default implementation, still supporting INPC by making them virtual:

    public class Animal:Concept
    {
        protected Animal(){}
        public virtual string Name { get; set; }
        public virtual int Age { get; set; }
    }

 

Extend Implementation

You can derive one Implementation class from another, extending it with some additional features. For example, add INPC implementation to interface implementation sample above.

Last edited Jul 27, 2011 at 2:03 PM by Kelqualyn, version 7

Comments

No comments yet.