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