using System;
using System.Linq;
using System.Reflection;
using Chronos.Reflection.Internal;
using UnityEngine;
using UnityObject = UnityEngine.Object;
namespace Chronos.Reflection
{
[Serializable]
public class UnityGetter : UnityMember
{
private enum SourceType
{
Unknown,
Field,
Property,
Method
}
private SourceType sourceType = SourceType.Unknown;
///
/// The underlying reflected field, or null if the getter is a property or method.
///
public FieldInfo fieldInfo { get; private set; }
///
/// The underlying property field, or null if the getter is a field or method.
///
public PropertyInfo propertyInfo { get; private set; }
///
/// The underlying reflected method, or null if the getter is a field or property.
///
public MethodInfo methodInfo { get; private set; }
///
/// Whether the reflected method is an extension method.
///
public bool isExtension { get; private set; }
[SerializeField]
private string[] _parameterTypes;
private Type[] __parameterTypes;
///
/// The types of the method's parameters.
///
public Type[] parameterTypes
{
get { return __parameterTypes; }
set { __parameterTypes = value; isReflected = false; }
}
#region Constructors
public UnityGetter() { }
public UnityGetter(string name) : base(name) { }
public UnityGetter(string name, UnityObject target) : base(name, target) { }
public UnityGetter(string component, string name) : base(component, name) { }
public UnityGetter(string component, string name, UnityObject target) : base(component, name, target) { }
public UnityGetter(string name, Type[] parameterTypes) : base(name) { this.parameterTypes = parameterTypes; }
public UnityGetter(string name, Type[] parameterTypes, UnityObject target) : this(name, parameterTypes) { this.target = target; Reflect(); }
public UnityGetter(string component, string name, Type[] parameterTypes) : base(component, name) { this.parameterTypes = parameterTypes; }
public UnityGetter(string component, string name, Type[] parameterTypes, UnityObject target) : this(component, name, parameterTypes) { this.target = target; Reflect(); }
#endregion
///
public override void Reflect()
{
EnsureAssigned();
EnsureTargeted();
this.fieldInfo = null;
this.propertyInfo = null;
this.methodInfo = null;
this.sourceType = SourceType.Unknown;
MemberInfo variableInfo;
MethodInfo methodInfo;
UnityReflectionException exception;
if (UnityMemberHelper.TryReflectVariable(out variableInfo, out exception, reflectionTarget, name))
{
fieldInfo = variableInfo as FieldInfo;
propertyInfo = variableInfo as PropertyInfo;
if (fieldInfo != null)
{
sourceType = SourceType.Field;
}
else if (propertyInfo != null)
{
sourceType = SourceType.Property;
}
}
else if (UnityMemberHelper.TryReflectMethod(out methodInfo, out exception, reflectionTarget, name, parameterTypes))
{
this.methodInfo = methodInfo;
isExtension = methodInfo.IsExtension();
sourceType = SourceType.Method;
}
else
{
throw new UnityReflectionException("No matching field, property or method found.");
}
isReflected = true;
}
///
/// Retrieves the value of the getter.
///
public object Get(params object[] parameters)
{
EnsureReflected();
switch (sourceType)
{
case SourceType.Field: return fieldInfo.GetValue(reflectionTarget);
case SourceType.Property: return propertyInfo.GetValue(reflectionTarget, null);
case SourceType.Method: return UnityMemberHelper.InvokeMethod(reflectionTarget, methodInfo, isExtension, parameters);
default: throw new UnityReflectionException();
}
}
///
/// Retrieves the value of the getter casted to the specified type.
///
public T Get(params object[] parameters)
{
return (T)Get(parameters);
}
///
/// The return type of the reflected field, property of method.
///
public Type returnType
{
get
{
EnsureReflected();
switch (sourceType)
{
case SourceType.Field: return fieldInfo.FieldType;
case SourceType.Property: return propertyInfo.PropertyType;
case SourceType.Method: return methodInfo.ReturnType;
default: throw new UnityReflectionException();
}
}
}
public override bool Corresponds(UnityMember other)
{
var corresponds = other is UnityGetter && base.Corresponds(other);
corresponds &= (parameterTypes == null) == (((UnityGetter)other).parameterTypes == null);
if (parameterTypes != null)
{
corresponds &= parameterTypes.SequenceEqual(((UnityGetter)other).parameterTypes);
}
return corresponds;
}
}
}