/*
Kooboo is a content management system based on ASP.NET MVC framework. Copyright 2009 Yardi Technology Limited.
This program is free software: you can redistribute it and/or modify it under the terms of the
GNU General Public License version 3 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program.
If not, see http://www.kooboo.com/gpl3/.
*/
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using System.Security;
using System.Security.Permissions;
namespace Everest.Library.Reflection{
/// <summary>
///
/// </summary>
public delegate void PropertySetterDelegate(object targetObject, object value);
/// <summary>
///
/// </summary>
public delegate object PropertyGetterDelegate(object targetObject);
/// <summary>
/// Can not use in medium-trust level
/// </summary>
public class PropertyDelegateFactory
{
static Dictionary<string, PropertySetterDelegate> propertySetterDelegates = new Dictionary<string, PropertySetterDelegate>();
static Dictionary<string, PropertyGetterDelegate> propertyGetterDelegates = new Dictionary<string, PropertyGetterDelegate>();
public static PropertySetterDelegate GetPropertySetter(Type objType, string propertyName)
{
return GetPropertySetter(objType, propertyName, true);
}
/// <summary>
/// Gets the property setter.
/// </summary>
/// <param name="objType">Type of the obj.</param>
/// <param name="propertyName">Name of the property.</param>
/// <param name="throwException">if set to <c>true</c> [throw exception].</param>
/// <returns></returns>
public static PropertySetterDelegate GetPropertySetter(Type objType, string propertyName, bool throwException)
{
string key = objType.FullName + propertyName;
if (!propertySetterDelegates.ContainsKey(key))
{
lock (propertySetterDelegates)
{
if (!propertySetterDelegates.ContainsKey(key))
{
CodeGenerator gen = new CodeGenerator();
gen.BeginMethod("m" + Guid.NewGuid().ToString("N"), typeof(PropertySetterDelegate));
FieldInfo fieldInfo = objType.GetField(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
if (fieldInfo == null)
{
PropertyInfo pi = objType.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (pi == null)
{
if (throwException)
{
throw new ArgumentException("Not found property or field named " + propertyName);
}
else
{
return null;
}
}
if (!pi.CanWrite)
{
if (throwException)
{
throw new ArgumentException("The property which named " + propertyName + "is readonly.");
}
else
return null;
}
//Property
//targetObject
gen.Ldarg(0);
gen.Ldarg(1);
if (pi.PropertyType.IsValueType)
{
gen.UnboxAny(pi.PropertyType.IsEnum ? typeof(int) : pi.PropertyType);
}
gen.StoreMember(pi);
}
else
{
//Field
//Static field
if (fieldInfo.IsStatic)
{
gen.Ldarg(1);
}
else//instance field
{
//targetObject
gen.Ldarg(0);
gen.Ldarg(1);
}
//unbox
if (fieldInfo.FieldType.IsValueType)
{
gen.UnboxAny(fieldInfo.FieldType.IsEnum ? typeof(int) : fieldInfo.FieldType);
}
gen.StoreMember(fieldInfo);
}
propertySetterDelegates.Add(key, (PropertySetterDelegate)gen.EndMethod());
}
}
}
return propertySetterDelegates[key];
}
public static PropertyGetterDelegate GetPropertyGetter(Type objType, string propertyName)
{
return GetPropertyGetter(objType, propertyName, true);
}
/// <summary>
/// Gets the property getter.
/// </summary>
/// <param name="objType">Type of the obj.</param>
/// <param name="propertyName">Name of the property.</param>
/// <param name="throwException">if set to <c>true</c> [throw exception].</param>
/// <returns></returns>
public static PropertyGetterDelegate GetPropertyGetter(Type objType, string propertyName, bool throwException)
{
string key = objType.FullName + propertyName;
if (!propertyGetterDelegates.ContainsKey(key))
{
lock (propertyGetterDelegates)
{
if (!propertyGetterDelegates.ContainsKey(key))
{
CodeGenerator gen = new CodeGenerator();
gen.BeginMethod("m" + Guid.NewGuid().ToString("N"), typeof(PropertyGetterDelegate));
FieldInfo fieldInfo = objType.GetField(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
if (fieldInfo == null)
{
PropertyInfo pi = objType.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
if (pi == null)
{
if (throwException)
{
throw new ArgumentException("Not found property or field named " + propertyName);
}
else
{
return null;
}
}
if (!pi.CanRead)
{
if (throwException)
{
throw new ArgumentException("The property which named " + propertyName + "is readonly.");
}
else
return null;
}
gen.Ldarg(0);
gen.LoadMember(pi);
if (pi.PropertyType.IsValueType)
{
gen.Box(pi.PropertyType.IsEnum ? typeof(int) : pi.PropertyType);
}
}
else
{
if (fieldInfo.IsStatic)
{
gen.LoadMember(fieldInfo);
}
else
{
gen.Ldarg(0);
gen.LoadMember(fieldInfo);
}
if (fieldInfo.FieldType.IsValueType)
{
gen.Box(fieldInfo.FieldType.IsEnum ? typeof(int) : fieldInfo.FieldType);
}
}
propertyGetterDelegates.Add(key, (PropertyGetterDelegate)gen.EndMethod());
}
}
}
return propertyGetterDelegates[key];
}
}
}
|