Files
Stationeers-RemoteControl/Vendor/Swan.Lite-3.1.0/Extensions.IPropertyProxy.cs

175 lines
7.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using Swan.Reflection;
namespace Swan
{
/// <summary>
/// Provides functionality to access <see cref="IPropertyProxy"/> objects
/// associated with types. Getters and setters are stored as delegates compiled
/// from constructed lambda expressions for fast access.
/// </summary>
public static class PropertyProxyExtensions
{
private static readonly object SyncLock = new object();
private static readonly Dictionary<Type, Dictionary<string, IPropertyProxy>> ProxyCache =
new Dictionary<Type, Dictionary<string, IPropertyProxy>>(32);
/// <summary>
/// Gets the property proxies associated with a given type.
/// </summary>
/// <param name="t">The type to retrieve property proxies from.</param>
/// <returns>A dictionary with property names as keys and <see cref="IPropertyProxy"/> objects as values.</returns>
public static Dictionary<string, IPropertyProxy> PropertyProxies(this Type t)
{
if (t == null)
throw new ArgumentNullException(nameof(t));
lock (SyncLock)
{
if (ProxyCache.ContainsKey(t))
return ProxyCache[t];
var properties = t.GetProperties(BindingFlags.Instance | BindingFlags.Public);
var result = new Dictionary<string, IPropertyProxy>(properties.Length, StringComparer.InvariantCultureIgnoreCase);
foreach (var propertyInfo in properties)
result[propertyInfo.Name] = new PropertyInfoProxy(t, propertyInfo);
ProxyCache[t] = result;
return result;
}
}
/// <summary>
/// Gets the property proxies associated with the provided instance type.
/// </summary>
/// <typeparam name="T">The instance type.</typeparam>
/// <param name="obj">The instance.</param>
/// <returns>A dictionary with property names as keys and <see cref="IPropertyProxy"/> objects as values.</returns>
public static Dictionary<string, IPropertyProxy> PropertyProxies<T>(this T obj) =>
(obj?.GetType() ?? typeof(T)).PropertyProxies();
/// <summary>
/// Gets the property proxy given the property name.
/// </summary>
/// <param name="t">The associated type.</param>
/// <param name="propertyName">Name of the property.</param>
/// <returns>The associated <see cref="IPropertyProxy"/></returns>
public static IPropertyProxy PropertyProxy(this Type t, string propertyName)
{
var proxies = t.PropertyProxies();
return proxies.ContainsKey(propertyName) ? proxies[propertyName] : null;
}
/// <summary>
/// Gets the property proxy given the property name.
/// </summary>
/// <typeparam name="T">The type of instance to extract proxies from.</typeparam>
/// <param name="obj">The instance to extract proxies from.</param>
/// <param name="propertyName">Name of the property.</param>
/// <returns>The associated <see cref="IPropertyProxy"/></returns>
public static IPropertyProxy PropertyProxy<T>(this T obj, string propertyName)
{
if (propertyName == null)
throw new ArgumentNullException(nameof(propertyName));
var proxies = (obj?.GetType() ?? typeof(T)).PropertyProxies();
return proxies?.ContainsKey(propertyName) == true ? proxies[propertyName] : null;
}
/// <summary>
/// Gets the property proxy given the property name as an expression.
/// </summary>
/// <typeparam name="T">The instance type.</typeparam>
/// <typeparam name="V">The property value type.</typeparam>
/// <param name="obj">The object.</param>
/// <param name="propertyExpression">The property expression.</param>
/// <returns>The associated <see cref="IPropertyProxy"/></returns>
public static IPropertyProxy PropertyProxy<T, V>(this T obj, Expression<Func<T, V>> propertyExpression)
{
if (propertyExpression == null)
throw new ArgumentNullException(nameof(propertyExpression));
var proxies = (obj?.GetType() ?? typeof(T)).PropertyProxies();
var propertyName = propertyExpression.PropertyName();
return proxies?.ContainsKey(propertyName) == true ? proxies[propertyName] : null;
}
/// <summary>
/// Reads the property value.
/// </summary>
/// <typeparam name="T">The type to get property proxies from.</typeparam>
/// <typeparam name="V">The type of the property.</typeparam>
/// <param name="obj">The instance.</param>
/// <param name="propertyExpression">The property expression.</param>
/// <returns>
/// The value obtained from the associated <see cref="IPropertyProxy" />
/// </returns>
/// <exception cref="ArgumentNullException">obj.</exception>
public static V ReadProperty<T, V>(this T obj, Expression<Func<T, V>> propertyExpression)
{
if (obj == null)
throw new ArgumentNullException(nameof(obj));
var proxy = obj.PropertyProxy(propertyExpression);
return (V)(proxy?.GetValue(obj));
}
/// <summary>
/// Reads the property value.
/// </summary>
/// <typeparam name="T">The type to get property proxies from.</typeparam>
/// <param name="obj">The instance.</param>
/// <param name="propertyName">Name of the property.</param>
/// <returns>
/// The value obtained from the associated <see cref="IPropertyProxy" />
/// </returns>
/// <exception cref="ArgumentNullException">obj.</exception>
public static object? ReadProperty<T>(this T obj, string propertyName)
{
if (obj == null)
throw new ArgumentNullException(nameof(obj));
var proxy = obj.PropertyProxy(propertyName);
return proxy?.GetValue(obj);
}
/// <summary>
/// Writes the property value.
/// </summary>
/// <typeparam name="T">The type to get property proxies from.</typeparam>
/// <typeparam name="TV">The type of the property.</typeparam>
/// <param name="obj">The instance.</param>
/// <param name="propertyExpression">The property expression.</param>
/// <param name="value">The value.</param>
public static void WriteProperty<T, TV>(this T obj, Expression<Func<T, TV>> propertyExpression, TV value)
{
var proxy = obj.PropertyProxy(propertyExpression);
proxy?.SetValue(obj, value);
}
/// <summary>
/// Writes the property value using the property proxy.
/// </summary>
/// <typeparam name="T">The type to get property proxies from.</typeparam>
/// <param name="obj">The instance.</param>
/// <param name="propertyName">Name of the property.</param>
/// <param name="value">The value.</param>
public static void WriteProperty<T>(this T obj, string propertyName, object? value)
{
var proxy = obj.PropertyProxy(propertyName);
proxy?.SetValue(obj, value);
}
private static string PropertyName<T, TV>(this Expression<Func<T, TV>> propertyExpression)
{
var memberExpression = !(propertyExpression.Body is MemberExpression)
? (propertyExpression.Body as UnaryExpression).Operand as MemberExpression
: propertyExpression.Body as MemberExpression;
return memberExpression.Member.Name;
}
}
}