Over the weekend I decided to start work on my own version of [FastMember](https://github.com/mgravell/fast-member). I began with my take on an implementation of `TypeAccessor` so that I could work with the properties of any type, create an instance of the type, and one or two other little tricks. I've reached a point where I'm out of ideas on how to improve the design of the class further so now I'm looking for feedback.

**Usage:**

```
public class Point2D {
    public double X { get; set; }
    public double Y { get; set; }
}

var pointA = new Point2D { X = 9000.01, Y = 0.0 };
var accessor = TypeAccessor.Create(pointA);
var pointB = new Point2D(); // pointB.X should be 0.0

accessor.CloneProperties(pointA, pointB) // pointB.X should now be 9000.01
accessor[pointA, "X"] = 0.0; // sets pointA.X to 0.0
Console.WriteLine(accessor[pointA, "X"]) // prints pointA.X, should be 0.0
accessor.Default(ref pointA); // sets pointA's properties to default the accessor's default values
Console.WriteLine(accessor[pointA, "X"]); // prints pointA.X, should be 9000.01

```

**Notes:**

One of the design goals was to ensure that everything always works as you might expect it to based on the current context. If the `Type` you send to `TypeAccessor` has a property that is read-only then a method like `CloneProperties` will simply ignore that property because it's not cloneable. `GetProperties` returns an actual instance of `Dictionary<string, object>` because it makes no sense to let the method yield when:

1. Some nasty behaviors become possible because reference types could be nulled during any yield
2. Two other options exist for accessing properties one at a time

As far as I know, every single "expensive" operation that can be lifted into the constructor has been (which was very important to me for performance). I can't say I'm pleased with the amount of code there but it really doesn't belong anywhere else. I suppose it could be split up into two or three private methods but I'm not sure that would be any better...

**Dependencies:**

There are three method calls in this class that are not part of .NET: `GetGetAccessor`, `GetSetAccessor`, and `HasDefaultConstructor`. Links to their implementation is provided below for reference.

[PropertyInfoExtensions.cs](https://gist.github.com/Kittoes/d6c259e09c55a7246bfe4f26c04bbfac)

[TypeExtensions.cs](https://gist.github.com/Kittoes/c62815d1f68a70750e11ae113635c27e)

```
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.Serialization;

public interface ITypeAccessor<T>
{
    object this[T instance, string propertyName] { get; set; }
    IEnumerable<string> CloneableProperties { get; }
    IDictionary<string, Func<T, object>> GetterCache { get; }
    IDictionary<string, Action<T, object>> SetterCache { get; }

    void CloneProperties(T source, T target);
    void Default(ref T instance);
    object GetProperty(T instance, string propertyName);
    IDictionary<string, object> GetProperties(T instance, IEnumerable<string> properties);
    T New();
    void SetProperty(T instance, string propertyName, object value);
    void SetProperties(T instance, IEnumerable<KeyValuePair<string, object>> properties);
}

/// <summary>
/// Provides cached access to a <see cref="T"/>'s property getters and setters.
/// </summary>
public class TypeAccessor<T> : ITypeAccessor<T>
{
    private readonly Func<T, T> m_applyDefaultValues;
    private readonly ReadOnlyCollection<string> m_cloneableProperties;
    private readonly Func<T> m_constructType;
    private readonly ReadOnlyDictionary<string, Func<T, object>> m_getterCache;
    private readonly ReadOnlyDictionary<string, Action<T, object>> m_setterCache;

    /// <summary>
    /// Uses the <see cref="TypeAccessor{_}"/> to get or set the value of a property by name.
    /// </summary>
    /// <param name="instance">The instance of <see cref="T"/> to get or set a property on.</param>
    /// <param name="propertyName">The name of the property to affect on the instance of <see cref="T"/>.</param>
    /// <returns></returns>
    public object this[T instance, string propertyName] {
        get {
            return GetProperty(instance, propertyName);
        }
        set {
            SetProperty(instance, propertyName, value);
        }
    }
    /// <summary>
    /// Returns a read-only cache of property names that belong to <see cref="T"/> and have both a getter and a setter.
    /// </summary>
    public IEnumerable<string> CloneableProperties {
        get {
            return m_cloneableProperties;
        }
    }
    /// <summary>
    /// Returns a read-only cache of property getters that belong to <see cref="T"/>.
    /// </summary>
    public IDictionary<string, Func<T, object>> GetterCache {
        get {
            return m_getterCache;
        }
    }
    /// <summary>
    /// Returns a read-only cache of property setters that belong to <see cref="T"/>.
    /// </summary>
    public IDictionary<string, Action<T, object>> SetterCache {
        get {
            return m_setterCache;
        }
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="TypeAccessor{_}"/> class.
    /// </summary>
    /// <param name="defaultValue">The instance of <see cref="T"/> that will be used as this <see cref="TypeAccessor"/>'s default value.</param>
    /// <param name="includeNonPublic">Indicates whether non-public properties should be included.</param>
    public TypeAccessor(T defaultValue, bool includeNonPublic = false) {
        var properties = typeof(T).GetProperties(BindingFlags.Instance | (includeNonPublic ? BindingFlags.NonPublic : BindingFlags.Default) | BindingFlags.Public);

        m_getterCache = new ReadOnlyDictionary<string, Func<T, object>>(properties
            .Select(propertyInfo => new {
                PropertyName = propertyInfo.Name,
                PropertyGetAccessor = propertyInfo.GetGetAccessor<T>(includeNonPublic)
            })
            .Where(a => a.PropertyGetAccessor != null)
            .ToDictionary(
                k => k.PropertyName,
                v => v.PropertyGetAccessor
            ));
        m_setterCache = new ReadOnlyDictionary<string, Action<T, object>>(properties
            .Select(propertyInfo => new {
                PropertyName = propertyInfo.Name,
                PropertySetAccessor = propertyInfo.GetSetAccessor<T>(includeNonPublic)
            })
            .Where(a => a.PropertySetAccessor != null)
            .ToDictionary(
                k => k.PropertyName,
                v => v.PropertySetAccessor
            ));
        m_cloneableProperties = Array.AsReadOnly(GetterCache.Keys.Intersect(SetterCache.Keys).ToArray());

        if (typeof(T).IsValueType) {
            m_applyDefaultValues = (T instance) => { return defaultValue; };
            m_constructType = () => { return defaultValue; };
        }
        else if (defaultValue != null) {
            var defaultConstructor = GetDefaultConstructor();
            var propertyValues = GetProperties(defaultValue, CloneableProperties).ToArray();

            m_applyDefaultValues = (T instance) => { SetProperties(instance, propertyValues); return instance; };
            m_constructType = () => { return m_applyDefaultValues(defaultConstructor()); };
        }
        else {
            m_applyDefaultValues = (T instance) => { return default(T); };
            m_constructType = () => { return default(T); };
        }
    }

    /// <summary>
    /// Retrieves all property values from a source <see cref="T"/> and applies them to a target <see cref="T"/>.
    /// </summary>
    /// <param name="source">The source instance of <see cref="T"/> to retrieve property values from.</param>
    /// <param name="target">The target instance of <see cref="T"/> to apply property values to.</param>
    public void CloneProperties(T source, T target) {
        SetProperties(target, GetProperties(source, CloneableProperties));
    }
    /// <summary>
    /// Sets all propertes on the specified instance of <see cref="T"/> to this <see cref="TypeAccessor{_}"/>'s default values.
    /// </summary>
    /// <param name="instance">The instance of <see cref="T"/> to get a property from.</param>
    public void Default(ref T instance) {
        instance = m_applyDefaultValues(instance);
    }
    /// <summary>
    /// Uses the <see cref="TypeAccessor{_}"/> and specified <see cref="IEnumerable{_}"/> to get all property values.
    /// </summary>
    /// <param name="instance">The instance of <see cref="T"/> to get properties from.</param>
    public IDictionary<string, object> GetProperties(T instance) {
        return GetterCache.Keys.ToDictionary(
            propertyName => propertyName,
            propertyName => GetProperty(instance, propertyName)
        );
    }
    /// <summary>
    /// Uses the <see cref="TypeAccessor{_}"/> and specified <see cref="IEnumerable{_}"/> to get property values by name.
    /// </summary>
    /// <param name="instance">The instance of <see cref="T"/> to get properties from.</param>
    /// <param name="properties">The list of property names that values will be retrieved from the instance of <see cref="T"/>.</param>
    public IDictionary<string, object> GetProperties(T instance, IEnumerable<string> properties) {
        if (properties != null) {
            return properties.ToDictionary(
                propertyName => propertyName,
                propertyName => GetProperty(instance, propertyName)
            );
        }
        else {
            return new Dictionary<string, object>();
        }
    }
    /// <summary>
    /// Uses the <see cref="TypeAccessor{_}"/> to get the value of a property by name.
    /// </summary>
    /// <param name="instance">The instance of <see cref="T"/> to get a property from.</param>
    /// <param name="propertyName">The name of the property to retrieve from the instance of <see cref="T"/>.</param>
    public object GetProperty(T instance, string propertyName) {
        Func<T, object> getter;

        if (GetterCache.TryGetValue(propertyName, out getter)) {
            return getter(instance);
        }
        else {
            throw new KeyNotFoundException(message: string.Format("a property getter with the name does not {0} exist on {1}", propertyName, typeof(T).FullName));
        }
    }
    /// <summary>
    /// Creates a new <see cref="T"/> using this <see cref="TypeAccessor{_}"/>'s default type constructor.
    /// </summary>
    public T New() {
        return m_constructType();
    }
    /// <summary>
    /// Uses the <see cref="TypeAccessor{_}"/> and specified <see cref="IEnumerable{KeyValuePair{_,_}}"/> to set property values by name.
    /// </summary>
    /// <param name="instance">The instance of <see cref="T"/> to set property values for.</param>
    /// <param name="properties">The dictionary of property names and values that will be applied to the instance of <see cref="T"/>.</param>
    public void SetProperties(T instance, IEnumerable<KeyValuePair<string, object>> properties) {
        if (properties != null) {
            foreach (var property in properties) {
                SetProperty(instance, property.Key, property.Value);
            }
        }
    }
    /// <summary>
    /// Uses the <see cref="TypeAccessor{_}"/> to set the value of a property by name.
    /// </summary>
    /// <param name="instance">The instance of <see cref="T"/> to set a property value for.</param>
    /// <param name="propertyName">The name of the property to alter on the instance of <see cref="T"/>.</param>
    /// <param name="value">The value that will be applied to the property.</param>
    public void SetProperty(T instance, string propertyName, object value) {
        Action<T, object> setter;

        if (SetterCache.TryGetValue(propertyName, out setter)) {
            setter(instance, value);
        }
        else {
            throw new KeyNotFoundException(message: string.Format("a property setter with the name does not {0} exist on {1}", propertyName, typeof(T).FullName));
        }
    }

    /// <summary>
    /// Generates a <see cref="Func{_}"/> delegate to the default constructor of <see cref="T"/>.
    /// </summary>
    public static Func<T> GetDefaultConstructor() {
        var type = typeof(T);

        if (type == typeof(string)) {
            return Expression.Lambda<Func<T>>(Expression.TypeAs(Expression.Constant(null), typeof(string))).Compile();
        }
        else if (type.HasDefaultConstructor()) {
            return Expression.Lambda<Func<T>>(Expression.New(type)).Compile();
        }
        else {
            return () => (T)FormatterServices.GetUninitializedObject(type);
        }
    }
}
/// <summary>
/// Provides cached access to a <see cref="T"/>'s property getters and setters.
/// </summary>
public static class TypeAccessor
{
    /// <summary>
    /// Creates a new instance of the <see cref="ITypeAccessor{_}"/> interface using the specified <see cref="T"/>.
    /// </summary>
    /// <param name="defaultValue">The instance of <see cref="T"/> that will be used as this <see cref="ITypeAccessor{_}"/>'s default value.</param>
    /// <param name="includeNonPublic">Indicates whether non-public properties should be included.</param>
    public static ITypeAccessor<T> Create<T>(T defaultValue, bool includeNonPublic = false) {
        return new TypeAccessor<T>(defaultValue, includeNonPublic);
    }
}

```

---

**Edit:** Per request, I've added an interface at top to act as a sort of outline for all the class's desired functionality.