The Labs \ Source Viewer \ SSCLI \ System \ TypedReference

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. namespace System
  16. {
  17.    
  18.     // TypedReference is basically only ever seen on the call stack, and in param arrays.
  19.     // These are blob that must be dealt with by the compiler.
  20.     using System;
  21.     using System.Reflection;
  22.     using System.Runtime.CompilerServices;
  23.     using CultureInfo = System.Globalization.CultureInfo;
  24.     using FieldInfo = System.Reflection.FieldInfo;
  25.     using System.Security.Permissions;
  26.    
  27.     [CLSCompliant(false)]
  28.     [System.Runtime.InteropServices.ComVisible(true)]
  29.     public struct TypedReference
  30.     {
  31.         private IntPtr Value;
  32.         private IntPtr Type;
  33.        
  34.         [CLSCompliant(false)]
  35.         [ReflectionPermission(SecurityAction.LinkDemand, MemberAccess = true)]
  36.         public static TypedReference MakeTypedReference(object target, FieldInfo[] flds)
  37.         {
  38.             if (target == null)
  39.                 throw new ArgumentNullException("target");
  40.             if (flds == null)
  41.                 throw new ArgumentNullException("flds");
  42.             if (flds.Length == 0)
  43.                 throw new ArgumentException(Environment.GetResourceString("Arg_ArrayZeroError"));
  44.             else {
  45.                 RuntimeFieldHandle[] fields = new RuntimeFieldHandle[flds.Length];
  46.                 // For proper handling of Nullable<T> don't change GetType() to something like 'IsAssignableFrom'
  47.                 // Currently we can't make a TypedReference to fields of Nullable<T>, which is fine.
  48.                 Type targetType = target.GetType();
  49.                 for (int i = 0; i < flds.Length; i++) {
  50.                     FieldInfo field = flds[i];
  51.                     if (!(field is RuntimeFieldInfo))
  52.                         throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeFieldInfo"));
  53.                     else if (field.IsInitOnly || field.IsStatic)
  54.                         throw new ArgumentException(Environment.GetResourceString("Argument_TypedReferenceInvalidField"));
  55.                    
  56.                     if (targetType != field.DeclaringType && !targetType.IsSubclassOf(field.DeclaringType))
  57.                         throw new MissingMemberException(Environment.GetResourceString("MissingMemberTypeRef"));
  58.                    
  59.                     Type fieldType = field.FieldType;
  60.                     if (fieldType.IsPrimitive)
  61.                         throw new ArgumentException(Environment.GetResourceString("Arg_TypeRefPrimitve"));
  62.                    
  63.                     if (i < flds.Length - 1)
  64.                         if (!fieldType.IsValueType)
  65.                             throw new MissingMemberException(Environment.GetResourceString("MissingMemberNestErr"));
  66.                    
  67.                     fields[i] = field.FieldHandle;
  68.                     targetType = fieldType;
  69.                 }
  70.                 TypedReference result = new TypedReference();
  71.                 // reference to TypedReference is banned, so have to pass result as pointer
  72.                 unsafe {
  73.                     InternalMakeTypedReference(&result, target, fields, targetType.TypeHandle);
  74.                 }
  75.                 return result;
  76.             }
  77.         }
  78.        
  79.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  80.         // reference to TypedReference is banned, so have to pass result as pointer
  81.         unsafe private static extern void InternalMakeTypedReference(void* result, object target, RuntimeFieldHandle[] flds, RuntimeTypeHandle lastFieldType);
  82.        
  83.         public override int GetHashCode()
  84.         {
  85.             if (Type == IntPtr.Zero)
  86.                 return 0;
  87.             else
  88.                 return __reftype(this).GetHashCode();
  89.         }
  90.        
  91.         public override bool Equals(object o)
  92.         {
  93.             throw new NotSupportedException(Environment.GetResourceString("NotSupported_NYI"));
  94.         }
  95.        
  96.         unsafe public static object ToObject(TypedReference value)
  97.         {
  98.             return InternalToObject(&value);
  99.         }
  100.        
  101.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  102.         unsafe static internal extern object InternalToObject(void* value);
  103.        
  104.         internal bool IsNull {
  105.             get { return Value.IsNull() && Type.IsNull(); }
  106.         }
  107.        
  108.         public static Type GetTargetType(TypedReference value)
  109.         {
  110.             return __reftype(value);
  111.         }
  112.        
  113.         public static RuntimeTypeHandle TargetTypeToken(TypedReference value)
  114.         {
  115.             return __reftype(value).TypeHandle;
  116.         }
  117.        
  118.         // This may cause the type to be changed.
  119.         [CLSCompliant(false)]
  120.         unsafe public static void SetTypedReference(TypedReference target, object value)
  121.         {
  122.             InternalSetTypedReference(&target, value);
  123.         }
  124.        
  125.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  126.         unsafe static internal extern void InternalSetTypedReference(void* target, object value);
  127.        
  128.     }
  129.    
  130. }

Developer Fusion