[Adapdev-commits] Adapdev/src/Adapdev/Reflection ClassAccessor.cs,1.4,1.5 ClassAccessorCache.cs,1.4,
Status: Beta
Brought to you by:
intesar66
From: Sean M. <int...@us...> - 2005-11-16 07:19:59
|
Update of /cvsroot/adapdev/Adapdev/src/Adapdev/Reflection In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4187/src/Adapdev/Reflection Added Files: ClassAccessor.cs ClassAccessorCache.cs FieldAccessor.cs FieldAccessorException.cs IValueAccessor.cs PropertyAccessor.cs PropertyAccessorException.cs ReflectionCache.cs Log Message: --- NEW FILE: ClassAccessorCache.cs --- using System; using System.Collections; using System.Text; namespace Adapdev.Reflection { /// <summary> /// Summary description for ClassAccessorCache. /// </summary> public class ClassAccessorCache { private static Hashtable _classes = new Hashtable(); private ClassAccessorCache() { } public static ClassAccessor Get(Type t) { ClassAccessor c = null; if(!_classes.ContainsKey(t.FullName)) { c = new ClassAccessor(t); Add(c); c.LoadAllProperties(); } else { c = _classes[t.FullName] as ClassAccessor; } return c; } public static ClassAccessor Get(object o) { return Get(o.GetType()); } public static void Add(ClassAccessor c) { _classes[c.Type.FullName] = c; } public static void Remove(Type t) { _classes.Remove(t.FullName); } public static void Clear() { _classes.Clear(); } public static int Count { get{return _classes.Count;} } public static string ToString() { StringBuilder sb = new StringBuilder(); sb.Append("Properties for ClassAccessorCache: " + Environment.NewLine); foreach(ClassAccessor c in _classes.Values) { sb.Append(c + Environment.NewLine); } return sb.ToString(); } } } --- NEW FILE: PropertyAccessor.cs --- // // Author: James Nies // Date: 3/22/2005 // Description: The PropertyAccessor class provides fast dynamic access // to a property of a specified target class. // // *** This code was written by James Nies and has been provided to you, *** // *** free of charge, for your use. I assume no responsibility for any *** // *** undesired events resulting from the use of this code or the *** // *** information that has been provided with it . *** // using System; using System.Reflection; using System.Reflection.Emit; using System.Threading; using System.Collections; namespace Adapdev.Reflection { /// <summary> /// The PropertyAccessor class provides fast dynamic access /// to a property of a specified target class. /// </summary> public class PropertyAccessor : IValueAccessor { /// <summary> /// Creates a new property accessor. /// </summary> /// <param name="targetType">Target object type.</param> /// <param name="property">Property name.</param> public PropertyAccessor(Type targetType, string property) { this.mTargetType = targetType; this.mProperty = property; PropertyInfo propertyInfo = targetType.GetProperty(property); // // Make sure the property exists // if(propertyInfo == null) { throw new PropertyAccessorException( string.Format("Property \"{0}\" does not exist for type " + "{1}.", property, targetType)); } else { this.mCanRead = propertyInfo.CanRead; this.mCanWrite = propertyInfo.CanWrite; this.mPropertyType = propertyInfo.PropertyType; } } /// <summary> /// Gets the property value from the specified target. /// </summary> /// <param name="target">Target object.</param> /// <returns>Property value.</returns> public object Get(object target) { if(mCanRead) { if(this.mEmittedValueAccessor == null) { this.Init(); } return this.mEmittedValueAccessor.Get(target); } else { throw new PropertyAccessorException( string.Format("Property \"{0}\" does not have a get method.", mProperty)); } } /// <summary> /// Sets the property for the specified target. /// </summary> /// <param name="target">Target object.</param> /// <param name="value">Value to set.</param> public void Set(object target, object value) { if(mCanWrite) { if(this.mEmittedValueAccessor == null) { this.Init(); } // // Set the property value // this.mEmittedValueAccessor.Set(target, value); } else { throw new PropertyAccessorException( string.Format("Property \"{0}\" does not have a set method.", mProperty)); } } /// <summary> /// Whether or not the Property supports read access. /// </summary> public bool CanRead { get { return this.mCanRead; } } /// <summary> /// Whether or not the Property supports write access. /// </summary> public bool CanWrite { get { return this.mCanWrite; } } /// <summary> /// The Type of object this property accessor was /// created for. /// </summary> public Type TargetType { get { return this.mTargetType; } } /// <summary> /// The Type of the Property being accessed. /// </summary> public Type PropertyType { get { return this.mPropertyType; } } private Type mTargetType; private string mProperty; private Type mPropertyType; private IValueAccessor mEmittedValueAccessor; private Hashtable mTypeHash; private bool mCanRead; private bool mCanWrite; /// <summary> /// This method generates creates a new assembly containing /// the Type that will provide dynamic access. /// </summary> private void Init() { this.InitTypes(); // Create the assembly and an instance of the // property accessor class. Assembly assembly = EmitAssembly(); mEmittedValueAccessor = assembly.CreateInstance("Property") as IValueAccessor; if(mEmittedValueAccessor == null) { throw new Exception("Unable to create property accessor."); } } /// <summary> /// Thanks to Ben Ratzlaff for this snippet of code /// http://www.codeproject.com/cs/miscctrl/CustomPropGrid.asp /// /// "Initialize a private hashtable with type-opCode pairs /// so i dont have to write a long if/else statement when outputting msil" /// </summary> private void InitTypes() { mTypeHash=new Hashtable(); mTypeHash[typeof(sbyte)]=OpCodes.Ldind_I1; mTypeHash[typeof(byte)]=OpCodes.Ldind_U1; mTypeHash[typeof(char)]=OpCodes.Ldind_U2; mTypeHash[typeof(short)]=OpCodes.Ldind_I2; mTypeHash[typeof(ushort)]=OpCodes.Ldind_U2; mTypeHash[typeof(int)]=OpCodes.Ldind_I4; mTypeHash[typeof(uint)]=OpCodes.Ldind_U4; mTypeHash[typeof(long)]=OpCodes.Ldind_I8; mTypeHash[typeof(ulong)]=OpCodes.Ldind_I8; mTypeHash[typeof(bool)]=OpCodes.Ldind_I1; mTypeHash[typeof(double)]=OpCodes.Ldind_R8; mTypeHash[typeof(float)]=OpCodes.Ldind_R4; } /// <summary> /// Create an assembly that will provide the get and set methods. /// </summary> private Assembly EmitAssembly() { // // Create an assembly name // AssemblyName assemblyName = new AssemblyName(); assemblyName.Name = "PropertyAccessorAssembly"; // // Create a new assembly with one module // AssemblyBuilder newAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); ModuleBuilder newModule = newAssembly.DefineDynamicModule("Module"); // // Define a public class named "Property" in the assembly. // TypeBuilder myType = newModule.DefineType("Property", TypeAttributes.Public); // // Mark the class as implementing IPropertyAccessor. // myType.AddInterfaceImplementation(typeof(IValueAccessor)); // Add a constructor ConstructorBuilder constructor = myType.DefineDefaultConstructor(MethodAttributes.Public); // // Define a method for the get operation. // Type[] getParamTypes = new Type[] {typeof(object)}; Type getReturnType = typeof(object); MethodBuilder getMethod = myType.DefineMethod("Get", MethodAttributes.Public | MethodAttributes.Virtual, getReturnType, getParamTypes); // // From the method, get an ILGenerator. This is used to // emit the IL that we want. // ILGenerator getIL = getMethod.GetILGenerator(); // // Emit the IL. // MethodInfo targetGetMethod = this.mTargetType.GetMethod("get_" + this.mProperty); if(targetGetMethod != null) { getIL.DeclareLocal(typeof(object)); getIL.Emit(OpCodes.Ldarg_1); //Load the first argument //(target object) getIL.Emit(OpCodes.Castclass, this.mTargetType); //Cast to the source type getIL.EmitCall(OpCodes.Call, targetGetMethod, null); //Get the property value if(targetGetMethod.ReturnType.IsValueType) { getIL.Emit(OpCodes.Box, targetGetMethod.ReturnType); //Box if necessary } getIL.Emit(OpCodes.Stloc_0); //Store it getIL.Emit(OpCodes.Ldloc_0); } else { getIL.ThrowException(typeof(MissingMethodException)); } getIL.Emit(OpCodes.Ret); // // Define a method for the set operation. // Type[] setParamTypes = new Type[] {typeof(object), typeof(object)}; Type setReturnType = null; MethodBuilder setMethod = myType.DefineMethod("Set", MethodAttributes.Public | MethodAttributes.Virtual, setReturnType, setParamTypes); // // From the method, get an ILGenerator. This is used to // emit the IL that we want. // ILGenerator setIL = setMethod.GetILGenerator(); // // Emit the IL. // MethodInfo targetSetMethod = this.mTargetType.GetMethod("set_" + this.mProperty); if(targetSetMethod != null) { Type paramType = targetSetMethod.GetParameters()[0].ParameterType; setIL.DeclareLocal(paramType); setIL.Emit(OpCodes.Ldarg_1); //Load the first argument //(target object) setIL.Emit(OpCodes.Castclass, this.mTargetType); //Cast to the source type setIL.Emit(OpCodes.Ldarg_2); //Load the second argument //(value object) if(paramType.IsValueType) { setIL.Emit(OpCodes.Unbox, paramType); //Unbox it if(mTypeHash[paramType]!=null) //and load { OpCode load = (OpCode)mTypeHash[paramType]; setIL.Emit(load); } else { setIL.Emit(OpCodes.Ldobj,paramType); } } else { setIL.Emit(OpCodes.Castclass, paramType); //Cast class } setIL.EmitCall(OpCodes.Callvirt, targetSetMethod, null); //Set the property value } else { setIL.ThrowException(typeof(MissingMethodException)); } setIL.Emit(OpCodes.Ret); // // Load the type // myType.CreateType(); return newAssembly; } } } --- NEW FILE: IValueAccessor.cs --- // // Author: James Nies // Date: 3/22/2005 // Description: The PropertyAccessor class uses this interface // for creating a type at runtime for accessing an individual // property on a target object. // // *** This code was written by James Nies and has been provided to you, *** // *** free of charge, for your use. I assume no responsibility for any *** // *** undesired events resulting from the use of this code or the *** // *** information that has been provided with it . *** // using System; namespace Adapdev.Reflection { /// <summary> /// The IPropertyAccessor interface defines a property /// accessor. /// </summary> public interface IValueAccessor { /// <summary> /// Gets the value stored in the property for /// the specified target. /// </summary> /// <param name="target">Object to retrieve /// the property from.</param> /// <returns>Property value.</returns> object Get(object target); /// <summary> /// Sets the value for the property of /// the specified target. /// </summary> /// <param name="target">Object to set the /// property on.</param> /// <param name="value">Property value.</param> void Set(object target, object value); } } --- NEW FILE: FieldAccessor.cs --- // // Author: James Nies // Date: 3/22/2005 // Description: The PropertyAccessor class provides fast dynamic access // to a property of a specified target class. // // *** This code was written by James Nies and has been provided to you, *** // *** free of charge, for your use. I assume no responsibility for any *** // *** undesired events resulting from the use of this code or the *** // *** information that has been provided with it . *** // using System; using System.Reflection; using System.Reflection.Emit; using System.Threading; using System.Collections; namespace Adapdev.Reflection { /// <summary> /// The PropertyAccessor class provides fast dynamic access /// to a property of a specified target class. /// </summary> public class FieldAccessor : IValueAccessor { /// <summary> /// Creates a new property accessor. /// </summary> /// <param name="targetType">Target object type.</param> /// <param name="field">Property name.</param> public FieldAccessor(Type targetType, string field) { this.mTargetType = targetType; this.mField = field; FieldInfo fieldInfo = targetType.GetField(field, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); // // Make sure the property exists // if(fieldInfo == null) { throw new FieldAccessorException( string.Format("Field \"{0}\" does not exist for type " + "{1}.", field, targetType)); } else { this.mCanRead = true; this.mCanWrite = true; //!fieldInfo.IsInitOnly; this.mFieldType = fieldInfo.FieldType; this.fi = fieldInfo; } } /// <summary> /// Gets the property value from the specified target. /// </summary> /// <param name="target">Target object.</param> /// <returns>Property value.</returns> public object Get(object target) { if(mCanRead) { if(this.mEmittedValueAccessor == null) { this.Init(); } return this.mEmittedValueAccessor.Get(target); } else { throw new FieldAccessorException( string.Format("Field \"{0}\" does not have a get method.", mField)); } } /// <summary> /// Sets the property for the specified target. /// </summary> /// <param name="target">Target object.</param> /// <param name="value">Value to set.</param> public void Set(object target, object value) { if(mCanWrite) { if(this.mEmittedValueAccessor == null) { this.Init(); } // // Set the property value // this.mEmittedValueAccessor.Set(target, value); } else { throw new FieldAccessorException( string.Format("Field \"{0}\" does not have a set method.", mField)); } } /// <summary> /// Whether or not the Property supports read access. /// </summary> public bool CanRead { get { return this.mCanRead; } } /// <summary> /// Whether or not the Property supports write access. /// </summary> public bool CanWrite { get { return this.mCanWrite; } } /// <summary> /// The Type of object this property accessor was /// created for. /// </summary> public Type TargetType { get { return this.mTargetType; } } /// <summary> /// The Type of the Property being accessed. /// </summary> public Type FieldType { get { return this.mFieldType; } } private Type mTargetType; private string mField; private Type mFieldType; private IValueAccessor mEmittedValueAccessor; private Hashtable mTypeHash; private bool mCanRead; private bool mCanWrite; private FieldInfo fi; /// <summary> /// This method generates creates a new assembly containing /// the Type that will provide dynamic access. /// </summary> private void Init() { this.InitTypes(); // Create the assembly and an instance of the // property accessor class. Assembly assembly = EmitAssembly(); mEmittedValueAccessor = assembly.CreateInstance("Field") as IValueAccessor; if(mEmittedValueAccessor == null) { throw new Exception("Unable to create property accessor."); } } /// <summary> /// Thanks to Ben Ratzlaff for this snippet of code /// http://www.codeproject.com/cs/miscctrl/CustomPropGrid.asp /// /// "Initialize a private hashtable with type-opCode pairs /// so i dont have to write a long if/else statement when outputting msil" /// </summary> private void InitTypes() { mTypeHash=new Hashtable(); mTypeHash[typeof(sbyte)]=OpCodes.Ldind_I1; mTypeHash[typeof(byte)]=OpCodes.Ldind_U1; mTypeHash[typeof(char)]=OpCodes.Ldind_U2; mTypeHash[typeof(short)]=OpCodes.Ldind_I2; mTypeHash[typeof(ushort)]=OpCodes.Ldind_U2; mTypeHash[typeof(int)]=OpCodes.Ldind_I4; mTypeHash[typeof(uint)]=OpCodes.Ldind_U4; mTypeHash[typeof(long)]=OpCodes.Ldind_I8; mTypeHash[typeof(ulong)]=OpCodes.Ldind_I8; mTypeHash[typeof(bool)]=OpCodes.Ldind_I1; mTypeHash[typeof(double)]=OpCodes.Ldind_R8; mTypeHash[typeof(float)]=OpCodes.Ldind_R4; } /// <summary> /// Create an assembly that will provide the get and set methods. /// </summary> private Assembly EmitAssembly() { // // Create an assembly name // AssemblyName assemblyName = new AssemblyName(); assemblyName.Name = "FieldAccessorAssembly"; // // Create a new assembly with one module // AssemblyBuilder newAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); ModuleBuilder newModule = newAssembly.DefineDynamicModule("Module"); // // Define a public class named "Property" in the assembly. // TypeBuilder myType = newModule.DefineType("Field", TypeAttributes.Public); // // Mark the class as implementing IPropertyAccessor. // myType.AddInterfaceImplementation(typeof(IValueAccessor)); // Add a constructor ConstructorBuilder constructor = myType.DefineDefaultConstructor(MethodAttributes.Public); // // Define a method for the get operation. // Type[] getParamTypes = new Type[] {typeof(object)}; Type getReturnType = typeof(object); MethodBuilder getMethod = myType.DefineMethod("Get", MethodAttributes.Public | MethodAttributes.Virtual, getReturnType, getParamTypes); // // From the method, get an ILGenerator. This is used to // emit the IL that we want. // ILGenerator getIL = getMethod.GetILGenerator(); // // Emit the IL. // // MethodInfo targetGetMethod = this.mTargetType.GetMethod("get_" + this.mField); // // if(targetGetMethod != null) // { // TODO: Fix this piece getIL.DeclareLocal(typeof(object)); getIL.Emit(OpCodes.Ldarg_1); //Load the first argument //(target object) getIL.Emit(OpCodes.Castclass, this.mTargetType); //Cast to the source type getIL.Emit(OpCodes.Stfld, this.mField); //getIL.EmitCall(OpCodes.Call, targetGetMethod, null); //Get the property value // if(targetGetMethod.ReturnType.IsValueType) // { // getIL.Emit(OpCodes.Box, targetGetMethod.ReturnType); //Box if necessary // } getIL.Emit(OpCodes.Stloc_0); //Store it getIL.Emit(OpCodes.Ldloc_0); // } // else // { // getIL.ThrowException(typeof(MissingMethodException)); // } getIL.Emit(OpCodes.Ret); // // Define a method for the set operation. // Type[] setParamTypes = new Type[] {typeof(object), typeof(object)}; Type setReturnType = null; MethodBuilder setMethod = myType.DefineMethod("Set", MethodAttributes.Public | MethodAttributes.Virtual, setReturnType, setParamTypes); // // From the method, get an ILGenerator. This is used to // emit the IL that we want. // ILGenerator setIL = setMethod.GetILGenerator(); // // Emit the IL. // MethodInfo targetSetMethod = this.mTargetType.GetMethod("set_" + this.mField); if(targetSetMethod != null) { Type paramType = targetSetMethod.GetParameters()[0].ParameterType; setIL.DeclareLocal(paramType); setIL.Emit(OpCodes.Ldarg_1); //Load the first argument //(target object) setIL.Emit(OpCodes.Castclass, this.mTargetType); //Cast to the source type setIL.Emit(OpCodes.Ldarg_2); //Load the second argument //(value object) if(paramType.IsValueType) { setIL.Emit(OpCodes.Unbox, paramType); //Unbox it if(mTypeHash[paramType]!=null) //and load { OpCode load = (OpCode)mTypeHash[paramType]; setIL.Emit(load); } else { setIL.Emit(OpCodes.Ldobj,paramType); } } else { setIL.Emit(OpCodes.Castclass, paramType); //Cast class } setIL.EmitCall(OpCodes.Callvirt, targetSetMethod, null); //Set the property value } else { setIL.ThrowException(typeof(MissingMethodException)); } setIL.Emit(OpCodes.Ret); // // Load the type // myType.CreateType(); return newAssembly; } } } --- NEW FILE: PropertyAccessorException.cs --- // // Author: James Nies // Date: 3/22/2005 // Description: Exception that can be thrown from the PropertyAccessor // class. // // *** This code was written by James Nies and has been provided to you, *** // *** free of charge, for your use. I assume no responsibility for any *** // *** undesired events resulting from the use of this code or the *** // *** information that has been provided with it . *** // using System; namespace Adapdev.Reflection { /// <summary> /// PropertyAccessorException class. /// </summary> public class PropertyAccessorException : Exception { public PropertyAccessorException(string message) : base(message) { } } } --- NEW FILE: ClassAccessor.cs --- using System; using System.Collections; using System.Reflection; using System.Text; namespace Adapdev.Reflection { /// <summary> /// Summary description for ClassAccessor. /// </summary> public class ClassAccessor { private Type _type = null; private Hashtable _properties = new Hashtable(); private DateTime _created; public ClassAccessor(Type t) { this._type = t; this._created = DateTime.Now; } public ClassAccessor(object o) : this(o.GetType()){} public void AddProperty(string name) { PropertyAccessor accessor = new PropertyAccessor(this._type, name); this._properties[name] = accessor; } public object GetPropertyValue(object o, string propertyName) { this.CheckForAccessor(propertyName); PropertyAccessor accessor = this._properties[propertyName] as PropertyAccessor; return accessor.Get(o); } public PropertyAccessor GetPropertyAccessor(string propertyName) { return this._properties[propertyName] as PropertyAccessor; } public Hashtable GetPropertyAccessors() { return this._properties; } public Type PropertyType(string propertyName) { this.CheckForAccessor(propertyName); PropertyAccessor accessor = this._properties[propertyName] as PropertyAccessor; return accessor.PropertyType; } public Type Type { get { return this._type; } } public void SetPropertyValue(object o, string propertyName, object val) { this.CheckForAccessor(propertyName); PropertyAccessor accessor = this._properties[propertyName] as PropertyAccessor; accessor.Set(o, val); } private void CheckForAccessor(string propertyName) { if(!this.IsPropertyDefined(propertyName)) this.AddProperty(propertyName); } private bool IsPropertyDefined(string propertyName) { return this._properties.ContainsKey(propertyName); } public void LoadAllProperties() { PropertyInfo[] infoArray = this._type.GetProperties(); foreach(PropertyInfo p in infoArray) { this.AddProperty(p.Name); } } public override string ToString() { StringBuilder sb = new StringBuilder(); sb.Append("[" + this._type.FullName + "] Properties loaded: " + Environment.NewLine); foreach(string key in this._properties.Keys) { sb.Append(key + Environment.NewLine); } return sb.ToString(); } public int PropertyCount { get{return this._properties.Count;} } } } --- NEW FILE: FieldAccessorException.cs --- using System; namespace Adapdev.Reflection { /// <summary> /// PropertyAccessorException class. /// </summary> public class FieldAccessorException : Exception { public FieldAccessorException(string message) : base(message) { } } } --- NEW FILE: ReflectionCache.cs --- #region Copyright / License Information /* Copyright 2004 - 2005 Adapdev Technologies, LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================ Author Log ============================ III Full Name SMM Sean McCormack (Adapdev) ============================ Change Log ============================ III MMDDYY Change */ #endregion namespace Adapdev.Reflection { using System; using System.Collections; using System.Collections.Specialized; using System.Reflection; /// <summary> /// Summary description for ReflectionCache. /// </summary> public class ReflectionCache { private static ReflectionCache instance; private HybridDictionary assemblies = new HybridDictionary(); private Hashtable types = new Hashtable(); public static ReflectionCache GetInstance() { if (instance == null) { instance = new ReflectionCache(); } return instance; } public Assembly GetAssembly(string assembly) { if (assemblies.Contains(assembly)) { return (Assembly) assemblies[assembly]; } else { Assembly a = Assembly.LoadFrom(assembly); assemblies[assembly] = a; return a; } } public Type GetType(string assembly, string type) { string id = assembly + "|" + type; if (types.Contains(id)) { return (Type) types[id]; } else { Assembly a = this.GetAssembly(assembly); Type t = a.GetType(type, true, true); types[id] = t; return t; } } } } |