Init RaspberryIO

This commit is contained in:
2019-02-17 14:08:57 +01:00
commit e7c3f7af91
193 changed files with 36743 additions and 0 deletions
@@ -0,0 +1,174 @@
namespace Unosquare.Swan.Reflection
{
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Collections.Concurrent;
using System.Linq;
/// <summary>
/// A thread-safe cache of attributes belonging to a given key (MemberInfo or Type).
///
/// The Retrieve method is the most useful one in this class as it
/// calls the retrieval process if the type is not contained
/// in the cache.
/// </summary>
public class AttributeCache
{
private readonly Lazy<ConcurrentDictionary<Tuple<object, Type>, IEnumerable<object>>> _data =
new Lazy<ConcurrentDictionary<Tuple<object, Type>, IEnumerable<object>>>(() =>
new ConcurrentDictionary<Tuple<object, Type>, IEnumerable<object>>(), true);
/// <summary>
/// Initializes a new instance of the <see cref="AttributeCache"/> class.
/// </summary>
/// <param name="propertyCache">The property cache object.</param>
public AttributeCache(PropertyTypeCache propertyCache = null)
{
PropertyTypeCache = propertyCache ?? Runtime.PropertyTypeCache;
}
/// <summary>
/// A PropertyTypeCache object for caching properties and their attributes.
/// </summary>
public PropertyTypeCache PropertyTypeCache { get; }
/// <summary>
/// Determines whether [contains] [the specified member].
/// </summary>
/// <typeparam name="T">The type of the attribute to be retrieved.</typeparam>
/// <param name="member">The member.</param>
/// <returns>
/// <c>true</c> if [contains] [the specified member]; otherwise, <c>false</c>.
/// </returns>
public bool Contains<T>(MemberInfo member) => _data.Value.ContainsKey(new Tuple<object, Type>(member, typeof(T)));
/// <summary>
/// Gets specific attributes from a member constrained to an attribute.
/// </summary>
/// <typeparam name="T">The type of the attribute to be retrieved.</typeparam>
/// <param name="member">The member.</param>
/// <param name="inherit"><c>true</c> to inspect the ancestors of element; otherwise, <c>false</c>.</param>
/// <returns>An array of the attributes stored for the specified type.</returns>
public IEnumerable<object> Retrieve<T>(MemberInfo member, bool inherit = false)
where T : Attribute
{
if (member == null)
throw new ArgumentNullException(nameof(member));
return Retrieve(new Tuple<object, Type>(member, typeof(T)), t => member.GetCustomAttributes<T>(inherit));
}
/// <summary>
/// Gets all attributes of a specific type from a member.
/// </summary>
/// <param name="member">The member.</param>
/// <param name="type">The attribute type.</param>
/// <param name="inherit"><c>true</c> to inspect the ancestors of element; otherwise, <c>false</c>.</param>
/// <returns>An array of the attributes stored for the specified type.</returns>
public IEnumerable<object> Retrieve(MemberInfo member, Type type, bool inherit = false)
{
if (member == null)
throw new ArgumentNullException(nameof(member));
if (type == null)
throw new ArgumentNullException(nameof(type));
return Retrieve(
new Tuple<object, Type>(member, type),
t => member.GetCustomAttributes(type, inherit));
}
/// <summary>
/// Gets one attribute of a specific type from a member.
/// </summary>
/// <typeparam name="T">The attribute type.</typeparam>
/// <param name="member">The member.</param>
/// <param name="inherit"><c>true</c> to inspect the ancestors of element; otherwise, <c>false</c>.</param>
/// <returns>An attribute stored for the specified type.</returns>
public T RetrieveOne<T>(MemberInfo member, bool inherit = false)
where T : Attribute
{
if (member == null)
return default;
var attr = Retrieve(
new Tuple<object, Type>(member, typeof(T)),
t => member.GetCustomAttributes(typeof(T), inherit));
return ConvertToAttribute<T>(attr);
}
/// <summary>
/// Gets one attribute of a specific type from a generic type.
/// </summary>
/// <typeparam name="TAttribute">The type of the attribute.</typeparam>
/// <typeparam name="T">The type to retrieve the attribute.</typeparam>
/// <param name="inherit">if set to <c>true</c> [inherit].</param>
/// <returns>An attribute stored for the specified type.</returns>
public TAttribute RetrieveOne<TAttribute, T>(bool inherit = false)
where TAttribute : Attribute
{
var attr = Retrieve(
new Tuple<object, Type>(typeof(T), typeof(TAttribute)),
t => typeof(T).GetCustomAttributes(typeof(TAttribute), inherit));
return ConvertToAttribute<TAttribute>(attr);
}
/// <summary>
/// Gets all properties an their attributes of a given type constrained to only attributes.
/// </summary>
/// <typeparam name="T">The type of the attribute to retrieve.</typeparam>
/// <param name="type">The type of the object.</param>
/// <param name="inherit"><c>true</c> to inspect the ancestors of element; otherwise, <c>false</c>.</param>
/// <returns>A dictionary of the properties and their attributes stored for the specified type.</returns>
public Dictionary<PropertyInfo, IEnumerable<object>> Retrieve<T>(Type type, bool inherit = false)
where T : Attribute
{
if (type == null)
throw new ArgumentNullException(nameof(type));
return PropertyTypeCache.RetrieveAllProperties(type, true)
.ToDictionary(x => x, x => Retrieve<T>(x, inherit));
}
/// <summary>
/// Gets all properties and their attributes of a given type.
/// </summary>
/// <typeparam name="T">The object type used to extract the properties from.</typeparam>
/// <param name="attributeType">Type of the attribute.</param>
/// <param name="inherit"><c>true</c> to inspect the ancestors of element; otherwise, <c>false</c>.</param>
/// <returns>
/// A dictionary of the properties and their attributes stored for the specified type.
/// </returns>
public Dictionary<PropertyInfo, IEnumerable<object>> RetrieveFromType<T>(Type attributeType, bool inherit = false)
{
if (attributeType == null)
throw new ArgumentNullException(nameof(attributeType));
return PropertyTypeCache.RetrieveAllProperties<T>(true)
.ToDictionary(x => x, x => Retrieve(x, attributeType, inherit));
}
private static T ConvertToAttribute<T>(IEnumerable<object> attr)
where T : Attribute
{
if (attr?.Any() != true)
return default;
if (attr.Count() == 1)
return (T) Convert.ChangeType(attr.First(), typeof(T));
throw new AmbiguousMatchException("Multiple custom attributes of the same type found.");
}
private IEnumerable<object> Retrieve(Tuple<object, Type> key, Func<Tuple<object, Type>, IEnumerable<object>> factory)
{
if (factory == null)
throw new ArgumentNullException(nameof(factory));
return _data.Value.GetOrAdd(key, k => factory.Invoke(k).Where(item => item != null));
}
}
}
@@ -0,0 +1,107 @@
namespace Unosquare.Swan.Reflection
{
using System;
using System.Reflection;
using Attributes;
/// <summary>
/// Represents a Property object from a Object Reflection Property with extended values.
/// </summary>
public class ExtendedPropertyInfo
{
/// <summary>
/// Initializes a new instance of the <see cref="ExtendedPropertyInfo"/> class.
/// </summary>
/// <param name="propertyInfo">The property information.</param>
public ExtendedPropertyInfo(PropertyInfo propertyInfo)
{
if (propertyInfo == null)
{
throw new ArgumentNullException(nameof(propertyInfo));
}
Property = propertyInfo.Name;
DataType = propertyInfo.PropertyType.Name;
foreach (PropertyDisplayAttribute display in Runtime.AttributeCache.Retrieve<PropertyDisplayAttribute>(propertyInfo, true))
{
Name = display.Name;
Description = display.Description;
GroupName = display.GroupName;
DefaultValue = display.DefaultValue;
}
}
/// <summary>
/// Gets or sets the property.
/// </summary>
/// <value>
/// The property.
/// </value>
public string Property { get; }
/// <summary>
/// Gets or sets the type of the data.
/// </summary>
/// <value>
/// The type of the data.
/// </value>
public string DataType { get; }
/// <summary>
/// Gets or sets the value.
/// </summary>
/// <value>
/// The value.
/// </value>
public object Value { get; set; }
/// <summary>
/// Gets or sets the default value.
/// </summary>
/// <value>
/// The default value.
/// </value>
public object DefaultValue { get; }
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>
/// The name.
/// </value>
public string Name { get; }
/// <summary>
/// Gets or sets the description.
/// </summary>
/// <value>
/// The description.
/// </value>
public string Description { get; }
/// <summary>
/// Gets or sets the name of the group.
/// </summary>
/// <value>
/// The name of the group.
/// </value>
public string GroupName { get; }
}
/// <summary>
/// Represents a Property object from a Object Reflection Property with extended values.
/// </summary>
/// <typeparam name="T">The type of the object.</typeparam>
public class ExtendedPropertyInfo<T> : ExtendedPropertyInfo
{
/// <summary>
/// Initializes a new instance of the <see cref="ExtendedPropertyInfo{T}"/> class.
/// </summary>
/// <param name="property">The property.</param>
public ExtendedPropertyInfo(string property)
: base(typeof(T).GetProperty(property))
{
}
}
}
@@ -0,0 +1,290 @@
namespace Unosquare.Swan.Reflection
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
/// <summary>
/// Provides extended information about a type.
///
/// This class is mainly used to define sets of types within the Definition class
/// and it is not meant for other than querying the BasicTypesInfo dictionary.
/// </summary>
public class ExtendedTypeInfo
{
#region Static Declarations
private const string TryParseMethodName = nameof(byte.TryParse);
private const string ToStringMethodName = nameof(ToString);
private static readonly Type[] NumericTypes =
{
typeof(byte),
typeof(sbyte),
typeof(decimal),
typeof(double),
typeof(float),
typeof(int),
typeof(uint),
typeof(long),
typeof(ulong),
typeof(short),
typeof(ushort),
};
#endregion
#region State Management
private readonly ParameterInfo[] _tryParseParameters;
private readonly int _toStringArgumentLength;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ExtendedTypeInfo"/> class.
/// </summary>
/// <param name="t">The t.</param>
public ExtendedTypeInfo(Type t)
{
Type = t ?? throw new ArgumentNullException(nameof(t));
IsNullableValueType = Type.GetTypeInfo().IsGenericType
&& Type.GetGenericTypeDefinition() == typeof(Nullable<>);
IsValueType = t.GetTypeInfo().IsValueType;
UnderlyingType = IsNullableValueType ?
new NullableConverter(Type).UnderlyingType :
Type;
IsNumeric = NumericTypes.Contains(UnderlyingType);
// Extract the TryParse method info
try
{
TryParseMethodInfo = UnderlyingType.GetMethod(TryParseMethodName,
new[] { typeof(string), typeof(NumberStyles), typeof(IFormatProvider), UnderlyingType.MakeByRefType() }) ??
UnderlyingType.GetMethod(TryParseMethodName,
new[] { typeof(string), UnderlyingType.MakeByRefType() });
_tryParseParameters = TryParseMethodInfo?.GetParameters();
}
catch
{
// ignored
}
// Extract the ToString method Info
try
{
ToStringMethodInfo = UnderlyingType.GetMethod(ToStringMethodName,
new[] { typeof(IFormatProvider) }) ??
UnderlyingType.GetMethod(ToStringMethodName,
new Type[] { });
_toStringArgumentLength = ToStringMethodInfo?.GetParameters().Length ?? 0;
}
catch
{
// ignored
}
}
#endregion
#region Properties
/// <summary>
/// Gets the type this extended info class provides for.
/// </summary>
/// <value>
/// The type.
/// </value>
public Type Type { get; }
/// <summary>
/// Gets a value indicating whether the type is a nullable value type.
/// </summary>
/// <value>
/// <c>true</c> if this instance is nullable value type; otherwise, <c>false</c>.
/// </value>
public bool IsNullableValueType { get; }
/// <summary>
/// Gets a value indicating whether the type or underlying type is numeric.
/// </summary>
/// <value>
/// <c>true</c> if this instance is numeric; otherwise, <c>false</c>.
/// </value>
public bool IsNumeric { get; }
/// <summary>
/// Gets a value indicating whether the type is value type.
/// Nullable value types have this property set to False.
/// </summary>
public bool IsValueType { get; }
/// <summary>
/// When dealing with nullable value types, this property will
/// return the underlying value type of the nullable,
/// Otherwise it will return the same type as the Type property.
/// </summary>
/// <value>
/// The type of the underlying.
/// </value>
public Type UnderlyingType { get; }
/// <summary>
/// Gets the try parse method information. If the type does not contain
/// a suitable TryParse static method, it will return null.
/// </summary>
/// <value>
/// The try parse method information.
/// </value>
public MethodInfo TryParseMethodInfo { get; }
/// <summary>
/// Gets the ToString method info
/// It will prefer the overload containing the IFormatProvider argument.
/// </summary>
/// <value>
/// To string method information.
/// </value>
public MethodInfo ToStringMethodInfo { get; }
/// <summary>
/// Gets a value indicating whether the type contains a suitable TryParse method.
/// </summary>
/// <value>
/// <c>true</c> if this instance can parse natively; otherwise, <c>false</c>.
/// </value>
public bool CanParseNatively => TryParseMethodInfo != null;
#endregion
#region Methods
/// <summary>
/// Gets the default value of this type. For reference types it return null.
/// For value types it returns the default value.
/// </summary>
/// <returns>Default value of this type.</returns>
public object GetDefault() => Type.GetTypeInfo().IsValueType ? Activator.CreateInstance(Type) : null;
/// <summary>
/// Tries to parse the string into an object of the type this instance represents.
/// Returns false when no suitable TryParse methods exists for the type or when parsing fails
/// for any reason. When possible, this method uses CultureInfo.InvariantCulture and NumberStyles.Any.
/// </summary>
/// <param name="s">The s.</param>
/// <param name="result">The result.</param>
/// <returns><c>true</c> if parse was converted successfully; otherwise, <c>false</c>.</returns>
public bool TryParse(string s, out object result)
{
result = GetDefault();
try
{
if (Type == typeof(string))
{
result = Convert.ChangeType(s, Type);
return true;
}
if (IsNullableValueType && string.IsNullOrEmpty(s))
{
result = GetDefault();
return true;
}
if (CanParseNatively == false)
{
result = GetDefault();
return false;
}
// Build the arguments of the TryParse method
var dynamicArguments = new List<object> { s };
for (var pi = 1; pi < _tryParseParameters.Length - 1; pi++)
{
var argInfo = _tryParseParameters[pi];
if (argInfo.ParameterType == typeof(IFormatProvider))
dynamicArguments.Add(CultureInfo.InvariantCulture);
else if (argInfo.ParameterType == typeof(NumberStyles))
dynamicArguments.Add(NumberStyles.Any);
else
dynamicArguments.Add(null);
}
dynamicArguments.Add(null);
var parseArguments = dynamicArguments.ToArray();
if ((bool)TryParseMethodInfo.Invoke(null, parseArguments) == false)
{
result = GetDefault();
return false;
}
result = parseArguments[parseArguments.Length - 1];
return true;
}
catch
{
return false;
}
}
/// <summary>
/// Converts this instance to its string representation,
/// trying to use the CultureInfo.InvariantCulture
/// IFormat provider if the overload is available.
/// </summary>
/// <param name="instance">The instance.</param>
/// <returns>A <see cref="System.String" /> that represents the current object.</returns>
public string ToStringInvariant(object instance)
{
if (instance == null)
return string.Empty;
return _toStringArgumentLength != 1
? instance.ToString()
: ToStringMethodInfo.Invoke(instance, new object[] {CultureInfo.InvariantCulture}) as string;
}
#endregion
}
/// <summary>
/// Provides extended information about a type.
///
/// This class is mainly used to define sets of types within the Constants class
/// and it is not meant for other than querying the BasicTypesInfo dictionary.
/// </summary>
/// <typeparam name="T">The type of extended type information.</typeparam>
public class ExtendedTypeInfo<T> : ExtendedTypeInfo
{
/// <summary>
/// Initializes a new instance of the <see cref="ExtendedTypeInfo{T}"/> class.
/// </summary>
public ExtendedTypeInfo()
: base(typeof(T))
{
// placeholder
}
/// <summary>
/// Converts this instance to its string representation,
/// trying to use the CultureInfo.InvariantCulture
/// IFormat provider if the overload is available.
/// </summary>
/// <param name="instance">The instance.</param>
/// <returns>A <see cref="System.String" /> that represents the current object.</returns>
public string ToStringInvariant(T instance) => base.ToStringInvariant(instance);
}
}
@@ -0,0 +1,118 @@
namespace Unosquare.Swan.Reflection
{
using System;
using System.Reflection;
using System.Collections.Concurrent;
/// <summary>
/// Represents a Method Info Cache.
/// </summary>
public class MethodInfoCache : ConcurrentDictionary<string, MethodInfo>
{
/// <summary>
/// Retrieves the properties stored for the specified type.
/// If the properties are not available, it calls the factory method to retrieve them
/// and returns them as an array of PropertyInfo.
/// </summary>
/// <typeparam name="T">The type of type.</typeparam>
/// <param name="name">The name.</param>
/// <param name="alias">The alias.</param>
/// <param name="types">The types.</param>
/// <returns>
/// The cached MethodInfo.
/// </returns>
/// <exception cref="ArgumentNullException">name
/// or
/// factory.</exception>
/// <exception cref="System.ArgumentNullException">type.</exception>
public MethodInfo Retrieve<T>(string name, string alias, params Type[] types)
=> Retrieve(typeof(T), name, alias, types);
/// <summary>
/// Retrieves the specified name.
/// </summary>
/// <typeparam name="T">The type of type.</typeparam>
/// <param name="name">The name.</param>
/// <param name="types">The types.</param>
/// <returns>
/// The cached MethodInfo.
/// </returns>
public MethodInfo Retrieve<T>(string name, params Type[] types)
=> Retrieve(typeof(T), name, name, types);
/// <summary>
/// Retrieves the specified type.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="name">The name.</param>
/// <param name="types">The types.</param>
/// <returns>
/// An array of the properties stored for the specified type.
/// </returns>
public MethodInfo Retrieve(Type type, string name, params Type[] types)
=> Retrieve(type, name, name, types);
/// <summary>
/// Retrieves the specified type.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="name">The name.</param>
/// <param name="alias">The alias.</param>
/// <param name="types">The types.</param>
/// <returns>
/// The cached MethodInfo.
/// </returns>
public MethodInfo Retrieve(Type type, string name, string alias, params Type[] types)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
if (alias == null)
throw new ArgumentNullException(nameof(alias));
if (name == null)
throw new ArgumentNullException(nameof(name));
return GetOrAdd(
alias,
x => type.GetMethod(name, types ?? new Type[0]));
}
/// <summary>
/// Retrieves the specified name.
/// </summary>
/// <typeparam name="T">The type of type.</typeparam>
/// <param name="name">The name.</param>
/// <returns>
/// The cached MethodInfo.
/// </returns>
public MethodInfo Retrieve<T>(string name)
=> Retrieve(typeof(T), name);
/// <summary>
/// Retrieves the specified type.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="name">The name.</param>
/// <returns>
/// The cached MethodInfo.
/// </returns>
/// <exception cref="ArgumentNullException">
/// type
/// or
/// name.
/// </exception>
public MethodInfo Retrieve(Type type, string name)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
if (name == null)
throw new ArgumentNullException(nameof(name));
return GetOrAdd(
name,
type.GetMethod);
}
}
}
+135
View File
@@ -0,0 +1,135 @@
namespace Unosquare.Swan.Reflection
{
using System.Linq;
using System;
using System.Collections.Generic;
using System.Reflection;
using Components;
/// <summary>
/// A thread-safe cache of members belonging to a given type.
///
/// The Retrieve method is the most useful one in this class as it
/// calls the retrieval process if the type is not contained
/// in the cache.
/// </summary>
/// <typeparam name="T">The type of Member to be cached.</typeparam>
public abstract class TypeCache<T> : CollectionCacheRepository<T>
where T : MemberInfo
{
/// <summary>
/// Determines whether the cache contains the specified type.
/// </summary>
/// <typeparam name="TOut">The type of the out.</typeparam>
/// <returns>
/// <c>true</c> if [contains]; otherwise, <c>false</c>.
/// </returns>
public bool Contains<TOut>() => ContainsKey(typeof(TOut));
/// <summary>
/// Retrieves the properties stored for the specified type.
/// If the properties are not available, it calls the factory method to retrieve them
/// and returns them as an array of PropertyInfo.
/// </summary>
/// <typeparam name="TOut">The type of the out.</typeparam>
/// <param name="factory">The factory.</param>
/// <returns>An array of the properties stored for the specified type.</returns>
public IEnumerable<T> Retrieve<TOut>(Func<Type, IEnumerable<T>> factory)
=> Retrieve(typeof(TOut), factory);
}
/// <summary>
/// A thread-safe cache of properties belonging to a given type.
///
/// The Retrieve method is the most useful one in this class as it
/// calls the retrieval process if the type is not contained
/// in the cache.
/// </summary>
public class PropertyTypeCache : TypeCache<PropertyInfo>
{
/// <summary>
/// Retrieves all properties.
/// </summary>
/// <typeparam name="T">The type to inspect.</typeparam>
/// <param name="onlyPublic">if set to <c>true</c> [only public].</param>
/// <returns>
/// A collection with all the properties in the given type.
/// </returns>
public IEnumerable<PropertyInfo> RetrieveAllProperties<T>(bool onlyPublic = false)
=> Retrieve<T>(onlyPublic ? GetAllPublicPropertiesFunc() : GetAllPropertiesFunc());
/// <summary>
/// Retrieves all properties.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="onlyPublic">if set to <c>true</c> [only public].</param>
/// <returns>
/// A collection with all the properties in the given type.
/// </returns>
public IEnumerable<PropertyInfo> RetrieveAllProperties(Type type, bool onlyPublic = false)
=> Retrieve(type, onlyPublic ? GetAllPublicPropertiesFunc() : GetAllPropertiesFunc());
/// <summary>
/// Retrieves the filtered properties.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="onlyPublic">if set to <c>true</c> [only public].</param>
/// <param name="filter">The filter.</param>
/// <returns>
/// A collection with all the properties in the given type.
/// </returns>
public IEnumerable<PropertyInfo> RetrieveFilteredProperties(
Type type,
bool onlyPublic,
Func<PropertyInfo, bool> filter)
=> Retrieve(type,
onlyPublic ? GetAllPublicPropertiesFunc(filter) : GetAllPropertiesFunc(filter));
private static Func<Type, IEnumerable<PropertyInfo>> GetAllPropertiesFunc(
Func<PropertyInfo, bool> filter = null)
=> GetPropertiesFunc(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
filter);
private static Func<Type, IEnumerable<PropertyInfo>> GetAllPublicPropertiesFunc(
Func<PropertyInfo, bool> filter = null)
=> GetPropertiesFunc(BindingFlags.Public | BindingFlags.Instance, filter);
private static Func<Type, IEnumerable<PropertyInfo>> GetPropertiesFunc(BindingFlags flags,
Func<PropertyInfo, bool> filter = null)
=> t => t.GetProperties(flags)
.Where(filter ?? (p => p.CanRead || p.CanWrite));
}
/// <summary>
/// A thread-safe cache of fields belonging to a given type
/// The Retrieve method is the most useful one in this class as it
/// calls the retrieval process if the type is not contained
/// in the cache.
/// </summary>
public class FieldTypeCache : TypeCache<FieldInfo>
{
/// <summary>
/// Retrieves all fields.
/// </summary>
/// <typeparam name="T">The type to inspect.</typeparam>
/// <returns>
/// A collection with all the fields in the given type.
/// </returns>
public IEnumerable<FieldInfo> RetrieveAllFields<T>()
=> Retrieve<T>(GetAllFieldsFunc());
/// <summary>
/// Retrieves all fields.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>
/// A collection with all the fields in the given type.
/// </returns>
public IEnumerable<FieldInfo> RetrieveAllFields(Type type)
=> Retrieve(type, GetAllFieldsFunc());
private static Func<Type, IEnumerable<FieldInfo>> GetAllFieldsFunc()
=> t => t.GetFields(BindingFlags.Public | BindingFlags.Instance);
}
}