Complete documentation for the reflection manager.
This commit is contained in:
@@ -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);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user