Do czego służy atrybut __DynamicallyInvokable?

181

Przeglądając System.Linq.Enumerablew DotPeek zauważam, że niektóre metody są doprawione [__DynamicallyInvokable]atrybutem.

Jaką rolę odgrywa ten atrybut? Czy jest to coś dodanego przez DotPeek, czy też odgrywa inną rolę, być może informując kompilator o tym, jak najlepiej zoptymalizować metody?

Jamie Dixon
źródło
2
String.Empty również to ma, btw.
Marc Gravell
1
Tak też jest IReadOnlyCollection<T>.
Drew Noakes,
1
And System.ServiceModel v3's BasicHttpBinding.TextEncoding(który w V4 przeniósł się do nowej klasy podstawowej i staje się HttpBindingBase.TextEncoding)
Ruben Bartelink
jest również używany do wartości całkowitych w wyliczeniach systemowych, takich jak DayOfWeek
beauXjames
raz mam przypadek, gdy metoda z tym atrybutem została wstawiona w wygenerowanym zestawie (DateTime.AddYears, .Net 4.5)
gdbdable

Odpowiedzi:

139

Jest nieudokumentowany, ale wygląda na jedną z optymalizacji w .NET 4.5. Wygląda na to, że służy do wypełniania pamięci podręcznej informacji o typie refleksji, dzięki czemu kolejny kod refleksji na popularnych typach ram działa szybciej. Jest komentarz na ten temat w źródle referencyjnym właściwości System.Reflection.Assembly.cs, RuntimeAssembly.Flags:

 // 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;
 }

Bez dalszych wskazówek, co może oznaczać „błogosławiony interfejs API”. Chociaż z kontekstu jasno wynika, że ​​będzie to działać tylko na typach w samym frameworku. Powinien być gdzieś dodatkowy kod sprawdzający atrybut zastosowany do typów i metod. Nie mam pojęcia, gdzie to się znajduje, ale biorąc pod uwagę, że musiałby mieć widok wszystkich typów .NET, aby spróbować buforowania, mogę tylko myśleć o Ngen.exe.

Hans Passant
źródło
7
Wygląda na to, że przechowywana wartość jest używana do sprawdzenia, czy interfejs API jest dostępny na WP8.
usr
1
+1 Zobacz mój komentarz do Q OP - jeden przypadek, w którym CLR wydaje się robić oszustwa w oparciu o to polega na obsłudze „niewielkich” ruchów metod (np. W dół o jeden poziom do nowej klasy podstawowej) w ramach unifikacji
Ruben Bartelink,
2
To sztuczka [TypeForwardTo], coś zupełnie innego.
Hans Passant
@HansPassant Interesujące - brzmi tak, jakbym mógł się mylić, więc ... nie pomyślałem o sprawdzeniu oryginalnego zestawu / typu. Najważniejsze jest to, że na 4.5 cytowana właściwość (nie typ) przesunęła się w stosunku do tego, gdzie była na 3.5 (technicznie System.ServiceModel 3.0). Założyłem, że mscorlibw grę wchodziły unifikacje a la referencje, ale i tak mam wiele do zrobienia w mojej konkretnej sprawie - i tak w odpowiednim czasie zgłosi i / lub usunie mylący ton do moich komentarzy ...
Ruben Bartelink
1
@HansPassant Z dalszych badań ... Nie mogę zobaczyć niczego, co dotyczy Przekazywania typów, które robią rzeczy inne niż Typy przesyłania, więc w tym momencie zaczynam się różnić czymś zupełnie innym . Siły w pracy polegają po prostu na tym, że gdy masz odwołanie do zestawu CLR2 System.ServiceModel v3, ładujesz go w ramach automatycznych aktualizacji CLR4 do System.ServiceModel v4. Zabawne jest to, że .NET 4.5 dokonuje aktualizacji na miejscu, System.ServiceModeldodając nową klasę podstawową i przenosi właściwość na niższy poziom .
Ruben Bartelink
23

Odkryłem, że jest on wykorzystywany w Runtime*Info.IsNonW8PFrameworkAPI()pakiecie metod wewnętrznych. Umieszczenie tego atrybutu na elemencie powoduje, że IsNonW8PFrameworkAPI () zwraca falsego, a tym samym udostępnia element członkowski w aplikacjach WinRT i wyłącza The API '...' cannot be used on the current platform.wyjątek.

Autorzy profili powinni umieszczać ten atrybut na elementach emitowanych przez ich profilera do zespołów szkieletu, jeśli chcą uzyskać do nich dostęp w WinRT.

Stefan Dragnev
źródło
1
Tak, kod znaleziony przez @Hans ustawia szukane flagi RuntimeAssembly.InvocableAttributeCtorToken, które są wywoływane przez wspomniane IsNonW8PFrameworkAPI()metody.
Mark Hurd