Complete documentation for the reflection manager.

This commit is contained in:
Westin Miller
2017-08-20 18:30:52 -07:00
parent 3564eb805c
commit 0554dbc608

View File

@@ -15,44 +15,144 @@ namespace Torch.Managers
string Name { get; set; }
Type Type { get; set; }
}
/// <summary>
/// Indicates that this field should contain a delegate capable of retrieving the value of a field.
/// </summary>
/// <example>
/// <code>
/// <![CDATA[
/// [ReflectedGetterAttribute(Name="_instanceField")]
/// private static Func<Example, int> _instanceGetter;
///
/// [ReflectedGetterAttribute(Name="_staticField", Type=typeof(Example))]
/// private static Func<int> _staticGetter;
///
/// private class Example {
/// private int _instanceField;
/// private static int _staticField;
/// }
/// ]]>
/// </code>
/// </example>
[AttributeUsage(AttributeTargets.Field)]
public class ReflectedGetterAttribute : Attribute, IReflectedFieldAttribute
{
/// <summary>
/// Name of the field to get. If null, the tagged field's name.
/// </summary>
public string Name { get; set; } = null;
/// <summary>
/// Declaring type of the field to get. If null, inferred from the instance argument type.
/// </summary>
public Type Type { get; set; } = null;
}
/// <summary>
/// Indicates that this field should contain a delegate capable of setting the value of a field.
/// </summary>
/// <example>
/// <code>
/// <![CDATA[
/// [ReflectedSetterAttribute(Name="_instanceField")]
/// private static Action<Example, int> _instanceSetter;
///
/// [ReflectedSetterAttribute(Name="_staticField", Type=typeof(Example))]
/// private static Action<int> _staticSetter;
///
/// private class Example {
/// private int _instanceField;
/// private static int _staticField;
/// }
/// ]]>
/// </code>
/// </example>
[AttributeUsage(AttributeTargets.Field)]
public class ReflectedSetterAttribute : Attribute, IReflectedFieldAttribute
{
/// <summary>
/// Name of the field to get. If null, the tagged field's name.
/// </summary>
public string Name { get; set; } = null;
/// <summary>
/// Declaring type of the field to get. If null, inferred from the instance argument type.
/// </summary>
public Type Type { get; set; } = null;
}
/// <summary>
/// Indicates that this field should contain a delegate capable of invoking an instance method.
/// </summary>
/// <example>
/// <code>
/// <![CDATA[
/// [ReflectedMethodAttribute]
/// private static Func<Example, int, float, string> ExampleInstance;
///
/// private class Example {
/// private int ExampleInstance(int a, float b) {
/// return a + ", " + b;
/// }
/// }
/// ]]>
/// </code>
/// </example>
[AttributeUsage(AttributeTargets.Field)]
public class ReflectedMethodAttribute : Attribute
{
/// <summary>
/// Name of the method to invoke. If null, the tagged field's name.
/// </summary>
public string Name { get; set; } = null;
/// <summary>
/// Declaring type of the method to invoke. If null, inferred from the instance argument type.
/// </summary>
public Type Type { get; set; } = null;
}
/// <summary>
/// Indicates that this field should contain a delegate capable of invoking a static method.
/// </summary>
/// <example>
/// <code>
/// <![CDATA[
/// [ReflectedMethodAttribute(Type = typeof(Example)]
/// private static Func<int, float, string> ExampleStatic;
///
/// private class Example {
/// private static int ExampleStatic(int a, float b) {
/// return a + ", " + b;
/// }
/// }
/// ]]>
/// </code>
/// </example>
[AttributeUsage(AttributeTargets.Field)]
public class ReflectedStaticMethodAttribute : ReflectedMethodAttribute
{
public Type Type { get; set; }
}
/// <summary>
/// Automatically calls <see cref="ReflectionManager.Process(Assembly)"/> for every assembly already loaded, and every assembly that is loaded in the future.
/// </summary>
public class ReflectionManager : Manager
{
private static readonly string[] _namespaceBlacklist = new[] {
"System", "VRage", "Sandbox", "SpaceEngineers"
};
/// <inheritdoc />
public ReflectionManager(ITorchBase torchInstance) : base(torchInstance) { }
/// <inheritdoc />
public override void Attach()
{
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
Process(asm);
AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad;
}
/// <inheritdoc />
public override void Detach()
{
AppDomain.CurrentDomain.AssemblyLoad -= CurrentDomain_AssemblyLoad;
@@ -72,7 +172,13 @@ namespace Torch.Managers
public static void Process(Type t)
{
if (_processedTypes.Add(t))
ProcessInternal(t);
{
foreach (string ns in _namespaceBlacklist)
if (t.FullName.StartsWith(ns))
return;
foreach (FieldInfo field in t.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
Process(field);
}
}
/// <summary>
@@ -85,20 +191,49 @@ namespace Torch.Managers
Process(type);
}
/// <summary>
/// Processes the given field, determines if it's reflected, and initializes it if it is.
/// </summary>
/// <param name="field">Field to process</param>
/// <returns>true if it was reflected, false if it wasn't reflectable</returns>
/// <exception cref="ArgumentException">If the field failed to process</exception>
public static bool Process(FieldInfo field)
{
var attr = field.GetCustomAttribute<ReflectedMethodAttribute>();
if (attr != null)
{
ProcessReflectedMethod(field, attr);
return true;
}
var attr2 = field.GetCustomAttribute<ReflectedGetterAttribute>();
if (attr2 != null)
{
ProcessReflectedField(field, attr2);
return true;
}
var attr3 = field.GetCustomAttribute<ReflectedSetterAttribute>();
if (attr3 != null)
{
ProcessReflectedField(field, attr3);
return true;
}
return false;
}
private static void ProcessReflectedMethod(FieldInfo field, ReflectedMethodAttribute attr)
{
MethodInfo delegateMethod = field.FieldType.GetMethod("Invoke");
ParameterInfo[] parameters = delegateMethod.GetParameters();
Type trueType;
Type trueType = attr.Type;
Type[] trueParameterTypes;
if (attr is ReflectedStaticMethodAttribute staticMethod)
if (attr is ReflectedStaticMethodAttribute)
{
trueType = staticMethod.Type;
trueParameterTypes = parameters.Select(x => x.ParameterType).ToArray();
}
else
{
trueType = parameters[0].ParameterType;
trueType = trueType ?? parameters[0].ParameterType;
trueParameterTypes = parameters.Skip(1).Select(x => x.ParameterType).ToArray();
}
@@ -196,23 +331,5 @@ namespace Torch.Managers
field.SetValue(null, Expression.Lambda(impl, paramExp).Compile());
}
private static void ProcessInternal(Type t)
{
foreach (FieldInfo field in t.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
{
var attr = field.GetCustomAttribute<ReflectedMethodAttribute>();
if (attr != null)
ProcessReflectedMethod(field, attr);
var attr2 = field.GetCustomAttribute<ReflectedGetterAttribute>();
if (attr2 != null)
ProcessReflectedField(field, attr2);
var attr3 = field.GetCustomAttribute<ReflectedSetterAttribute>();
if (attr3 != null)
ProcessReflectedField(field, attr3);
}
}
}
}