ChatGPT解决这个技术问题 Extra ChatGPT

What is the __DynamicallyInvokable attribute for?

Looking through System.Linq.Enumerable in DotPeek I notice that some methods are flavoured with a [__DynamicallyInvokable] attribute.

What role does this attribute play? Is it something added by DotPeek or does it play another role, perhaps informing the compiler on how best to optimise the methods?

String.Empty also has this, btw.
So does IReadOnlyCollection<T>.
And System.ServiceModel v3's BasicHttpBinding.TextEncoding (which in V4 has moved up to a new base class and becomes HttpBindingBase.TextEncoding)
it is also used for the integer values in System enums like DayOfWeek
once i have a case when method with this attribute was inlined in generated assembly (DateTime.AddYears, .Net 4.5)

H
Hans Passant

It is undocumented, but it looks like one of the optimizations in .NET 4.5. It appears to be used to prime the reflection type info cache, making subsequent reflection code on common framework types run faster. There's a comment about it in the Reference Source for System.Reflection.Assembly.cs, RuntimeAssembly.Flags property:

 // Each blessed API will be annotated with a "__DynamicallyInvokableAttribute".
 // This "__DynamicallyInvokableAttribute" is a type defined in its own assembly.
 // So the ctor is always a MethodDef and the type a TypeDef.
 // We cache this ctor MethodDef token for faster custom attribute lookup.
 // If this attribute type doesn't exist in the assembly, it means the assembly
 // doesn't contain any blessed APIs.
 Type invocableAttribute = GetType("__DynamicallyInvokableAttribute", false);
 if (invocableAttribute != null)
 {
     Contract.Assert(((MetadataToken)invocableAttribute.MetadataToken).IsTypeDef);

     ConstructorInfo ctor = invocableAttribute.GetConstructor(Type.EmptyTypes);
     Contract.Assert(ctor != null);

     int token = ctor.MetadataToken;
     Contract.Assert(((MetadataToken)token).IsMethodDef);

     flags |= (ASSEMBLY_FLAGS)token & ASSEMBLY_FLAGS.ASSEMBLY_FLAGS_TOKEN_MASK;
 }

Without further hints what a "blessed API" might mean. Although it is clear from the context that this will only work on types in the framework itself. There ought to be additional code somewhere that checks the attribute applied to types and methods. No idea where that is located, but given that it would have to need to have a view of all .NET types to have a shot at caching, I can only think of Ngen.exe.


It looks like the stored value is being used to check if the API is available on WP8.
+1 See my comment on the OP's Q - one case where the CLR seems to be doing trickery based on this is in the handling 'slight' moves of methods (e.g. down one level onto a new base class) under unification
That's the [TypeForwardTo] trick, something completely different.
@HansPassant Interesting - sounds like I may well be wrong so... hadn't thought of examining the original assembly/type. Bottom line is that on 4.5 the cited property (not the type) has moved relative to where it was on 3.5 (technically, System.ServiceModel 3.0). I had assumed that unification a la mscorlib references was at play but have plenty some circling back around on my specific issue to do anyway - will report back and/or remove any misleading tone to my comments in due course...
@HansPassant From further research... Cant see anything re Type Forwarding doing stuff other than Forwarding Types so at this point I beg to differ with the something completely different bit. The forces at work are simply that when you have a CLR2 assembly referencing System.ServiceModel v3, loading it under CLR4 auto-upgrades to System.ServiceModel v4. The fun bit is that .NET 4.5 does an in place update to the bits of System.ServiceModel dropping in a new base class underneath and moves the property down a level.
S
Stefan Dragnev

I found that it's used in the Runtime*Info.IsNonW8PFrameworkAPI() suite of internal methods. Having this attribute placed on a member makes IsNonW8PFrameworkAPI() return false for it and thus makes the member available in WinRT applications and shuts up the The API '...' cannot be used on the current platform. exception.

Profiler writers should place this attribute on members emitted by their profiler into framework assemblies, if they want to access them under WinRT.


Yeah, the code found by @Hans sets up the flags looked for by RuntimeAssembly.InvocableAttributeCtorToken, which is called by the IsNonW8PFrameworkAPI() methods you mention.