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; } string Name { get; set; }
Type Type { 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)] [AttributeUsage(AttributeTargets.Field)]
public class ReflectedGetterAttribute : Attribute, IReflectedFieldAttribute 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; 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; 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)] [AttributeUsage(AttributeTargets.Field)]
public class ReflectedSetterAttribute : Attribute, IReflectedFieldAttribute 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; 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; 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)] [AttributeUsage(AttributeTargets.Field)]
public class ReflectedMethodAttribute : Attribute 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; 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)] [AttributeUsage(AttributeTargets.Field)]
public class ReflectedStaticMethodAttribute : ReflectedMethodAttribute 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 public class ReflectionManager : Manager
{ {
private static readonly string[] _namespaceBlacklist = new[] {
"System", "VRage", "Sandbox", "SpaceEngineers"
};
/// <inheritdoc /> /// <inheritdoc />
public ReflectionManager(ITorchBase torchInstance) : base(torchInstance) { } public ReflectionManager(ITorchBase torchInstance) : base(torchInstance) { }
/// <inheritdoc />
public override void Attach() public override void Attach()
{ {
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
Process(asm); Process(asm);
AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad; AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad;
} }
/// <inheritdoc />
public override void Detach() public override void Detach()
{ {
AppDomain.CurrentDomain.AssemblyLoad -= CurrentDomain_AssemblyLoad; AppDomain.CurrentDomain.AssemblyLoad -= CurrentDomain_AssemblyLoad;
@@ -72,7 +172,13 @@ namespace Torch.Managers
public static void Process(Type t) public static void Process(Type t)
{ {
if (_processedTypes.Add(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> /// <summary>
@@ -85,20 +191,49 @@ namespace Torch.Managers
Process(type); 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) private static void ProcessReflectedMethod(FieldInfo field, ReflectedMethodAttribute attr)
{ {
MethodInfo delegateMethod = field.FieldType.GetMethod("Invoke"); MethodInfo delegateMethod = field.FieldType.GetMethod("Invoke");
ParameterInfo[] parameters = delegateMethod.GetParameters(); ParameterInfo[] parameters = delegateMethod.GetParameters();
Type trueType; Type trueType = attr.Type;
Type[] trueParameterTypes; Type[] trueParameterTypes;
if (attr is ReflectedStaticMethodAttribute staticMethod) if (attr is ReflectedStaticMethodAttribute)
{ {
trueType = staticMethod.Type;
trueParameterTypes = parameters.Select(x => x.ParameterType).ToArray(); trueParameterTypes = parameters.Select(x => x.ParameterType).ToArray();
} }
else else
{ {
trueType = parameters[0].ParameterType; trueType = trueType ?? parameters[0].ParameterType;
trueParameterTypes = parameters.Skip(1).Select(x => x.ParameterType).ToArray(); trueParameterTypes = parameters.Skip(1).Select(x => x.ParameterType).ToArray();
} }
@@ -196,23 +331,5 @@ namespace Torch.Managers
field.SetValue(null, Expression.Lambda(impl, paramExp).Compile()); 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);
}
}
} }
} }