144 lines
4.8 KiB
C#
144 lines
4.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
using ln.http.exceptions;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.ComponentModel;
|
|
namespace ln.http.resources.reflection
|
|
{
|
|
public class Reflector
|
|
{
|
|
Type TargetType { get; }
|
|
|
|
Dictionary<string, PropertyInfo> properties = new Dictionary<string, PropertyInfo>();
|
|
Dictionary<string, MethodInfo> methods = new Dictionary<string, MethodInfo>();
|
|
|
|
public Reflector(Type targetType)
|
|
{
|
|
TargetType = targetType;
|
|
Initialize();
|
|
}
|
|
|
|
private void Initialize()
|
|
{
|
|
foreach (PropertyInfo propertyInfo in TargetType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
|
{
|
|
if (propertyInfo.GetCustomAttribute<CallableAttribute>() != null)
|
|
{
|
|
properties.Add(propertyInfo.Name, propertyInfo);
|
|
}
|
|
}
|
|
foreach (MethodInfo methodInfo in TargetType.GetMethods(BindingFlags.Public | BindingFlags.Instance))
|
|
{
|
|
if (methodInfo.GetCustomAttribute<CallableAttribute>() != null)
|
|
{
|
|
methods.Add(methodInfo.Name, methodInfo);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public object InvokeRequest(HttpRequest httpRequest, Queue<string> pathStack, object currentValue)
|
|
{
|
|
if (pathStack.Count == 0)
|
|
return currentValue;
|
|
|
|
StringReader reader = new StringReader(pathStack.Dequeue());
|
|
StringBuilder sb = new StringBuilder();
|
|
while (IsValidNameChar((char)reader.Peek()))
|
|
sb.Append((char)reader.Read());
|
|
|
|
string next = sb.ToString();
|
|
sb.Clear();
|
|
|
|
if (properties.ContainsKey(next))
|
|
{
|
|
currentValue = properties[next].GetValue(currentValue);
|
|
}
|
|
else if (methods.ContainsKey(next))
|
|
{
|
|
currentValue = InvokeMethod(next, httpRequest, currentValue);
|
|
}
|
|
else
|
|
{
|
|
throw new KeyNotFoundException(next);
|
|
}
|
|
|
|
while (reader.Peek() != -1)
|
|
{
|
|
char nc = (char)reader.Read();
|
|
switch (nc)
|
|
{
|
|
case '[':
|
|
while ((reader.Peek() != ']') && (reader.Peek() != -1))
|
|
sb.Append((char)reader.Read());
|
|
reader.Read();
|
|
|
|
string index = sb.ToString();
|
|
sb.Clear();
|
|
|
|
Type currentType = currentValue.GetType();
|
|
if (currentType.IsArray)
|
|
{
|
|
int i = int.Parse(index);
|
|
currentValue = ((Array)currentValue).GetValue(i);
|
|
}
|
|
else
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
break;
|
|
default:
|
|
throw new NotSupportedException();
|
|
}
|
|
}
|
|
|
|
return currentValue;
|
|
}
|
|
|
|
object InvokeMethod(string methodName, HttpRequest httpRequest, object currentValue)
|
|
{
|
|
MethodInfo methodInfo = methods[methodName];
|
|
ParameterInfo[] parameterInfos = methodInfo.GetParameters();
|
|
object[] parameters = new object[parameterInfos.Length];
|
|
|
|
for (int n=0;n<parameterInfos.Length;n++)
|
|
{
|
|
if (httpRequest.Query.ContainsKey(parameterInfos[n].Name))
|
|
{
|
|
TypeConverter typeConverter = TypeDescriptor.GetConverter(parameterInfos[n].ParameterType);
|
|
if ((typeConverter != null) && typeConverter.CanConvertFrom(typeof(string)))
|
|
{
|
|
parameters[n] = typeConverter.ConvertFrom(httpRequest.Query[parameterInfos[n].Name]);
|
|
}
|
|
else
|
|
{
|
|
parameters[n] = Convert.ChangeType(httpRequest.Query[parameterInfos[n].Name], parameterInfos[n].ParameterType);
|
|
}
|
|
}
|
|
}
|
|
|
|
return methodInfo.Invoke(currentValue, parameters);
|
|
}
|
|
|
|
|
|
public static bool IsValidNameChar(char ch)
|
|
{
|
|
return Char.IsLetterOrDigit(ch) | (ch == '_');
|
|
}
|
|
|
|
|
|
static Dictionary<Type, Reflector> reflectorsCache = new Dictionary<Type, Reflector>();
|
|
public static Reflector GetReflector(Type targetType)
|
|
{
|
|
if (!reflectorsCache.ContainsKey(targetType))
|
|
{
|
|
reflectorsCache[targetType] = new Reflector(targetType);
|
|
}
|
|
return reflectorsCache[targetType];
|
|
}
|
|
}
|
|
}
|