ln.http.resources/reflection/Reflector.cs

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];
}
}
}