Something about ReflectionOnly Context

I was reading Joel's blog about new stuff in Reflection and he mentioned ReflectionOnly context. Apart from the Generics, token handle resolutions, LCG, ReflectionOnly context (actually a loader feature) had a big impact in Reflection area in Whidbey. It reminds me to talk about ReflectionOnly context thing in detail in my blog.

ReflectionOnly context is first of all a loader concept, and here is Junfeng's blog entry explaining that aspect in detail.

ReflectionOnly context's impact on Reflection is also large. Basically, Reflection can be summarized into two usages: inspect the assembly metadata and do latebind invocations. ReflectionOnly context is targeted for the first scenario *only*.

All those APIs related to execution is disabled (throws InvalidOperationException) if the assembly is loaded in a ReflectionOnly context. Those APIs are xxx.Invoke, FieldInfo.GetField, FieldInfo.SetField ... Their changes seem to be apparent and need no explanation.

There are several more APIs that are affected by ReflectionOnly context that do need some explanations:

  • GetCustomAttribute: The reason we have to disable this because GetCustomAttribute returns you an Attribute and to get that, we have to run the Attribute ctor. To enable the ReflectionOnly GetCustomAttribute, we provided a new API called GetCustomAttributeData that returns a CustomAttributeData object. That object contains the constructorinfo and other raw info about the Attribute arguments. Our new document contains detailed explanation on that type. Currently, GetCustomAttributeData performs close to GetCustomAttribute, but it doesn’t execute the ctor. It is possible that in the furture, we could provide a even faster GetCustomAttributeData.

 

  • Handle related APIs: We disable all access to handles. Handle is really a runtime concept, it exists in the runtime and is used for invocation operations. By disabling handle access and usage in ReflectionOnly context, we basically guarded ourselves against many potential areas that could hack through the system trying to do invocation in ReflectionOnly context. On the other hand, we are able to do all the assembly inspection work without handles. All token APIs not related to Handle function in ReflectionOnly context. In the ReflectionOnly context, it is possible to build your reflector that prints out assembly content together with the methodbody.

 

  • You may see there are new APIs called GetRawConstantValue on FieldInfo, PropertyInfo and ParameterInfo(GetRawDefaultValue). The usage of those APIs is to get the values encoded in the metadata out, which is supported in ReflectionOnly context. Particularly, if the field constant value is an enum, normal GetValue will try to return a enum and fail to execute the constructor, but GetRawConstantValue will return the encoded raw integer back to you. You should use GetRaw* APIs only when you are in ReflectionOnly context.

ReflectionOnly context is needed for certain scenarios to work. For example, you are developing a managed build tool such as regasm.exe that is supposed to work on all platforms. If you build the tool based on normal context, the tool will have difficulty to build a 64 bit app on 32 bit platform since we cannot load a 64 bit app on 32 bit platform in normal context. This scenario is common for build tools since in many places, people build their 64 bit apps using 32 bit machines. It is quite fair to recommend using ReflectionOnly context if your app is using Reflection only for content inspection to avoid unnecessary limitations.

The cons of ReflectionOnly context is that you cannot do any execution if the assembly is loaded that way (but for many tools, inspect the content is all Reflection used for) and you have to build your own assembly resolver since the loader won't resolve the assembly references for you automatically. ReflectionOnly load can also be used to load some unverifiable assemblies that normal load will fail since it skipped a lot of verification steps that normal load needed to do to ensure safe execution.