Code:
/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / xsp / System / Web / Util / FastPropertyAccessor.cs / 3 / FastPropertyAccessor.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- using System; using System.Reflection; using System.Reflection.Emit; using System.Threading; using System.Collections; using System.Security; using System.Security.Permissions; namespace System.Web.Util { /* * Property Accessor Generator class * * The purpose of this class is to generate some IL code on the fly that can efficiently * access properties (and fields) of objects. This is an alternative to using * very slow reflection. */ internal class FastPropertyAccessor { private static object s_lockObject = new object(); private static FastPropertyAccessor s_accessorGenerator; private static Hashtable s_accessorCache; private static MethodInfo _getPropertyMethod; private static MethodInfo _setPropertyMethod; private static Type[] _getPropertyParameterList = new Type[] { typeof(object) }; private static Type[] _setPropertyParameterList = new Type[] { typeof(object), typeof(object) }; private static Type[] _interfacesToImplement; private static int _uniqueId; // Used to generate unique type ID's. // Property getter/setter must be public for codegen to access it. // Static properties are ignored, since this class only works on instances of objects. // Need to use DeclaredOnly to avoid AmbiguousMatchException if a property with // a different return type is hidden. private const BindingFlags _declaredFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly; private ModuleBuilder _dynamicModule = null; static FastPropertyAccessor() { // Get the SetProperty method, and make sure it has // the correct signature. _getPropertyMethod = typeof(IWebPropertyAccessor).GetMethod("GetProperty"); _setPropertyMethod = typeof(IWebPropertyAccessor).GetMethod("SetProperty"); // This will be needed later, when building the dynamic class. _interfacesToImplement = new Type[1]; _interfacesToImplement[0] = typeof(IWebPropertyAccessor); } private static String GetUniqueCompilationName() { return Guid.NewGuid().ToString().Replace('-', '_'); } [ReflectionPermission(SecurityAction.Assert, Flags=ReflectionPermissionFlag.ReflectionEmit)] Type GetPropertyAccessorTypeWithAssert(Type type, string propertyName, PropertyInfo propInfo, FieldInfo fieldInfo) { // Create the dynamic assembly if needed. Type accessorType; MethodInfo getterMethodInfo = null; MethodInfo setterMethodInfo = null; Type propertyType; if (propInfo != null) { // It'a a property getterMethodInfo = propInfo.GetGetMethod(); setterMethodInfo = propInfo.GetSetMethod(); propertyType = propInfo.PropertyType; } else { // If not, it must be a field propertyType = fieldInfo.FieldType; } if (_dynamicModule == null) { lock (this) { if (_dynamicModule == null) { // Use a unique name for each assembly. String name = GetUniqueCompilationName(); AssemblyName assemblyName = new AssemblyName(); assemblyName.Name = "A_" + name; // Create a new assembly. AssemblyBuilder newAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run, null, //directory to persist assembly null, //evidence copied from caller null, //requiredPermissions null, //optionalPermissions null, //refusedPermissions true //isSynchronized ); // Create a single module in the assembly. _dynamicModule = newAssembly.DefineDynamicModule("M_" + name); } } } // Give the factory a unique name. String typeName = System.Web.UI.Util.MakeValidTypeNameFromString(type.Name) + "_" + propertyName + "_" + (_uniqueId++); TypeBuilder accessorTypeBuilder = _dynamicModule.DefineType("T_" + typeName, TypeAttributes.Public, typeof(object), _interfacesToImplement); // // Define the GetProperty method. It must be virtual to be an interface implementation. // MethodBuilder method = accessorTypeBuilder.DefineMethod("GetProperty", MethodAttributes.Public | MethodAttributes.Virtual, typeof(Object), _getPropertyParameterList); // Generate IL. The generated IL corresponds to: // "return ((TargetType) target).Blah;" ILGenerator il = method.GetILGenerator(); if (getterMethodInfo != null) { il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Castclass, type); // Generate the getter call based on whether it's a Property or Field if (propInfo != null) il.EmitCall(OpCodes.Callvirt, getterMethodInfo, null); else il.Emit(OpCodes.Ldfld, fieldInfo); il.Emit(OpCodes.Box, propertyType); il.Emit(OpCodes.Ret); // Specify that this method implements GetProperty from the inherited interface. accessorTypeBuilder.DefineMethodOverride(method, _getPropertyMethod); } else { // Generate IL. The generated IL corresponds to "throw new InvalidOperationException" ConstructorInfo cons = typeof(InvalidOperationException).GetConstructor(Type.EmptyTypes); il.Emit(OpCodes.Newobj, cons); il.Emit(OpCodes.Throw); } // // Define the SetProperty method. It must be virtual to be an interface implementation. // method = accessorTypeBuilder.DefineMethod("SetProperty", MethodAttributes.Public | MethodAttributes.Virtual, null, _setPropertyParameterList); il = method.GetILGenerator(); // Don't generate any code in the setter if it's a readonly property. // We still need to have an implementation of SetProperty, but it does nothing. if (fieldInfo != null || setterMethodInfo != null) { // Generate IL. The generated IL corresponds to: // "((TargetType) target).Blah = (PropType) val;" il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Castclass, type); il.Emit(OpCodes.Ldarg_2); if (propertyType.IsPrimitive) { // Primitive type: deal with boxing il.Emit(OpCodes.Unbox, propertyType); // Emit the proper instruction for the type if (propertyType == typeof(sbyte)) { il.Emit(OpCodes.Ldind_I1); } else if (propertyType == typeof(byte)) { il.Emit(OpCodes.Ldind_U1); } else if (propertyType == typeof(short)) { il.Emit(OpCodes.Ldind_I2); } else if (propertyType == typeof(ushort)) { il.Emit(OpCodes.Ldind_U2); } else if (propertyType == typeof(uint)) { il.Emit(OpCodes.Ldind_U4); } else if (propertyType == typeof(int)) { il.Emit(OpCodes.Ldind_I4); } else if (propertyType == typeof(long)) { il.Emit(OpCodes.Ldind_I8); } else if (propertyType == typeof(ulong)) { il.Emit(OpCodes.Ldind_I8); // Somehow, there is no Ldind_u8 } else if (propertyType == typeof(bool)) { il.Emit(OpCodes.Ldind_I1); } else if (propertyType == typeof(char)) { il.Emit(OpCodes.Ldind_U2); } else if (propertyType == typeof(decimal)) { il.Emit(OpCodes.Ldobj, propertyType); } else if (propertyType == typeof(float)) { il.Emit(OpCodes.Ldind_R4); } else if (propertyType == typeof(double)) { il.Emit(OpCodes.Ldind_R8); } else { il.Emit(OpCodes.Ldobj, propertyType); } } else if (propertyType.IsValueType) { // Value type: deal with boxing il.Emit(OpCodes.Unbox, propertyType); il.Emit(OpCodes.Ldobj, propertyType); } else { // No boxing involved: just generate a standard cast il.Emit(OpCodes.Castclass, propertyType); } // Generate the assignment based on whether it's a Property or Field if (propInfo != null) il.EmitCall(OpCodes.Callvirt, setterMethodInfo, null); else il.Emit(OpCodes.Stfld, fieldInfo); } il.Emit(OpCodes.Ret); // Specify that this method implements SetProperty from the inherited interface. accessorTypeBuilder.DefineMethodOverride(method, _setPropertyMethod); // Bake in the type. accessorType = accessorTypeBuilder.CreateType(); return accessorType; } private static IWebPropertyAccessor GetPropertyAccessor(Type type, string propertyName) { if (s_accessorGenerator == null || s_accessorCache == null) { lock (s_lockObject) { if (s_accessorGenerator == null || s_accessorCache == null) { s_accessorGenerator = new FastPropertyAccessor(); s_accessorCache = new Hashtable(); } } } // First, check if we have it cached // Get a hash key based on the Type and the property name int cacheKey = HashCodeCombiner.CombineHashCodes( type.GetHashCode(), propertyName.GetHashCode()); IWebPropertyAccessor accessor = (IWebPropertyAccessor) s_accessorCache[cacheKey]; // It was cached, so just return it if (accessor != null) return accessor; FieldInfo fieldInfo = null; Type declaringType; // First, try to find a property with that name. Type.GetProperty() without BindingFlags.Declared // will throw AmbiguousMatchException if there is a hidden property with the same name and a // different type (VSWhidbey 237437). This method finds the property with the specified name // on the most specific type. PropertyInfo propInfo = GetPropertyMostSpecific(type, propertyName); if (propInfo != null) { // Get the most base Type where the property is first declared MethodInfo baseCheckMethodInfo = propInfo.GetGetMethod(); if (baseCheckMethodInfo == null) { baseCheckMethodInfo = propInfo.GetSetMethod(); } declaringType = baseCheckMethodInfo.GetBaseDefinition().DeclaringType; // DevDiv Bug 27734 // Ignore the declaring type if it's generic if (declaringType.IsGenericType) declaringType = type; // If they're different, get a new PropertyInfo if (declaringType != type) { // We want the propertyInfo for the property specifically declared on the declaringType. // So pass in the correct BindingFlags to avoid an AmbiguousMatchException, which would // be thrown if the declaringType hides a property with the same name and a different type. // VSWhidbey 518034 propInfo = declaringType.GetProperty(propertyName, _declaredFlags); } } else { // We couldn't find a property, so try a field // Type.GetField can not throw AmbiguousMatchException like Type.GetProperty above. fieldInfo = type.GetField(propertyName); // If we couldn't find a field either, give up if (fieldInfo == null) throw new ArgumentException(); declaringType = fieldInfo.DeclaringType; } // If the Type where the property/field is declared is not the same as the current // Type, check if the declaring Type already has a cached accessor. This limits // the number of different accessors we need to create. e.g. Every control has // an ID property, but we'll end up only create one accessor for all of them. int declaringTypeCacheKey = 0; if (declaringType != type) { // Get a hash key based on the declaring Type and the property name declaringTypeCacheKey = HashCodeCombiner.CombineHashCodes( declaringType.GetHashCode(), propertyName.GetHashCode()); accessor = (IWebPropertyAccessor) s_accessorCache[declaringTypeCacheKey]; // We have a cached accessor for the declaring type, so use it if (accessor != null) { // Cache the declaring type's accessor as ourselves lock (s_accessorCache.SyncRoot) { s_accessorCache[cacheKey] = accessor; } return accessor; } } if (accessor == null) { Type propertyAccessorType; lock (s_accessorGenerator) { propertyAccessorType = s_accessorGenerator.GetPropertyAccessorTypeWithAssert( declaringType, propertyName, propInfo, fieldInfo); } // Create the type. This is the only place where Activator.CreateInstance is used, // reducing the calls to it from 1 per instance to 1 per type. accessor = (IWebPropertyAccessor) HttpRuntime.CreateNonPublicInstance(propertyAccessorType); } // Cache the accessor lock (s_accessorCache.SyncRoot) { s_accessorCache[cacheKey] = accessor; if (declaringTypeCacheKey != 0) s_accessorCache[declaringTypeCacheKey] = accessor; } return accessor; } internal static object GetProperty(object target, string propName) { IWebPropertyAccessor accessor = GetPropertyAccessor(target.GetType(), propName); return accessor.GetProperty(target); } // Finds the property with the specified name on the most specific type. private static PropertyInfo GetPropertyMostSpecific(Type type, string name) { PropertyInfo propInfo; Type currentType = type; while (currentType != null) { propInfo = currentType.GetProperty(name, _declaredFlags); if (propInfo != null) { return propInfo; } else { currentType = currentType.BaseType; } } return null; } internal static void SetProperty(object target, string propName, object val) { IWebPropertyAccessor accessor = GetPropertyAccessor(target.GetType(), propName); accessor.SetProperty(target, val); } } [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)] public interface IWebPropertyAccessor { object GetProperty(object target); void SetProperty(object target, object value); } }
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ToolStripSystemRenderer.cs
- SystemDropShadowChrome.cs
- PagerSettings.cs
- DataServiceQueryException.cs
- ErrorEventArgs.cs
- ThumbButtonInfo.cs
- SafeNativeMethods.cs
- AbstractSvcMapFileLoader.cs
- ZipIOCentralDirectoryBlock.cs
- DateTimeOffsetConverter.cs
- CollectionChangeEventArgs.cs
- SizeKeyFrameCollection.cs
- Debug.cs
- ActivityPropertyReference.cs
- ChtmlSelectionListAdapter.cs
- HtmlTableCell.cs
- DataObjectEventArgs.cs
- ExpandedWrapper.cs
- FactoryId.cs
- ListViewAutomationPeer.cs
- XpsResource.cs
- EnlistmentState.cs
- UnsafeNativeMethods.cs
- XmlILTrace.cs
- MinimizableAttributeTypeConverter.cs
- SystemTcpConnection.cs
- DocumentEventArgs.cs
- RoleManagerEventArgs.cs
- safemediahandle.cs
- RowSpanVector.cs
- LateBoundBitmapDecoder.cs
- SourceInterpreter.cs
- ResolveNameEventArgs.cs
- RepeaterItemCollection.cs
- XmlEnumAttribute.cs
- FileChangesMonitor.cs
- TargetConverter.cs
- StackBuilderSink.cs
- ByteStream.cs
- DefaultWorkflowLoaderService.cs
- TreeNodeBindingCollection.cs
- UrlMappingsModule.cs
- CreatingCookieEventArgs.cs
- ProxyManager.cs
- NoResizeSelectionBorderGlyph.cs
- XslNumber.cs
- TypeDescriptionProviderAttribute.cs
- StylusTouchDevice.cs
- ArrayElementGridEntry.cs
- AuthenticatingEventArgs.cs
- ByteStorage.cs
- AsymmetricKeyExchangeFormatter.cs
- DataGridViewColumnDesigner.cs
- XmlIlVisitor.cs
- _DigestClient.cs
- XmlElementAttribute.cs
- RelatedEnd.cs
- PeerMessageDispatcher.cs
- FormattedText.cs
- SimpleBitVector32.cs
- CanonicalXml.cs
- SizeValueSerializer.cs
- baseaxisquery.cs
- XmlWhitespace.cs
- SamlSecurityToken.cs
- AbsoluteQuery.cs
- AssertSection.cs
- OpacityConverter.cs
- HostedTransportConfigurationBase.cs
- Select.cs
- OracleConnectionStringBuilder.cs
- StylusPointPropertyInfoDefaults.cs
- DropTarget.cs
- GiveFeedbackEventArgs.cs
- TypeNameConverter.cs
- MailDefinition.cs
- CompilationUtil.cs
- Point3DAnimation.cs
- FontUnit.cs
- XPathNavigatorReader.cs
- externdll.cs
- InputLangChangeRequestEvent.cs
- ServiceOperationDetailViewControl.cs
- User.cs
- Message.cs
- DynamicArgumentDesigner.xaml.cs
- EastAsianLunisolarCalendar.cs
- BaseParaClient.cs
- WrappedKeySecurityTokenParameters.cs
- Point4D.cs
- ProgramPublisher.cs
- ListViewDataItem.cs
- WorkflowDataContext.cs
- MailBnfHelper.cs
- ToolStripDropDownMenu.cs
- CanonicalXml.cs
- GeneralTransform3DCollection.cs
- InputBindingCollection.cs
- PeerPresenceInfo.cs
- LocalizationParserHooks.cs