Для чого атрибут __DynamicallyInvokable?


181

Переглядаючи System.Linq.EnumerableDotPeek, я помічаю, що деякі методи ароматизовані [__DynamicallyInvokable]атрибутом.

Яку роль відіграє цей атрибут? Це щось додає DotPeek чи це грає іншу роль, можливо, інформуючи компілятора про те, як найкраще оптимізувати методи?


2
String.Empty також має це, btw.
Марк Гравелл

1
Так і робить IReadOnlyCollection<T>.
Дрю Ноакс

1
І System.ServiceModel v3's BasicHttpBinding.TextEncoding(який у V4 перейшов до нового базового класу і стає HttpBindingBase.TextEncoding)
Ruben Bartelink

він також використовується для цілих значень у системних перерахунках, таких як
DayOfWeek

як тільки у мене є випадок, коли метод з цим атрибутом був вкладений у створену збірку (DateTime.AddYears,. Net 4.5)
gdbdable

Відповіді:


139

Він недокументований, але схоже на одну з оптимізацій в .NET 4.5. Здається, він використовується для просування кешу інформації інформації про відображення, завдяки чому наступний код відображення для загальних типів фреймворку працює швидше. Про це є коментар у Довідковому джерелі для 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;
 }

Без додаткових підказок, що може означати "благословенний API". Хоча з контексту видно, що це буде працювати лише на типи в рамках. Десь повинен бути додатковий код, який перевіряє атрибут, застосований до типів та методів. Не маю уявлення, де це знаходиться, але враховуючи, що для того, щоб зняти кешування, потрібно мати перегляд усіх типів .NET, я можу подумати лише про Ngen.exe.


7
Схоже, що збережене значення використовується для перевірки наявності API на WP8.
usr

1
+1 Дивіться мій коментар щодо питання ОП - один випадок, коли CLR, здається, робить хитрість на основі цього, полягає в обробці "легких" кроків методів (наприклад, вниз на один рівень до нового базового класу) в об'єднанні
Рубен Бартелінк

2
Це фокус [TypeForwardTo], щось зовсім інше.
Ганс Пасант

@HansPassant Цікаво - звучить так, що я, можливо, помиляюся, тому ... не думав вивчати оригінальну збірку / тип. Підсумок полягає в тому, що 4,5-цитоване властивість (не тип) перемістилося відносно місця, де було на 3.5 (технічно, System.ServiceModel 3.0). Я припускав, що об’єднання а-ля mscorlibпосилань грає, але в будь-якому разі маю багато кружляти по моєму конкретному питанню - повідомлять про це та / або видалятимуть будь-який оманливий тон до моїх коментарів ...
Рубен Бартелінк

1
@HansPassant З подальших досліджень ... Неможливо побачити що-небудь наново, Переадресація роблячи інші речі, ніж типи переадресації, тож на даний момент я благаю відрізнятись від чогось зовсім іншого біта. Сили в роботі полягають у тому, що коли у вас є посилання CLR2 на посилання System.ServiceModel v3, завантажуючи його під автоматичним оновленням CLR4 до System.ServiceModel v4. Приємно, що .NET 4.5 робить оновлення на місці, щоб System.ServiceModelскинути нову частину нового базового класу і переміщує властивість на рівень .
Рубен Бартелінк

23

Я виявив, що він використовується в Runtime*Info.IsNonW8PFrameworkAPI()наборі внутрішніх методів. Якщо цей атрибут розміщено на члені, змушує IsNonW8PFrameworkAPI () повернутись falseдо нього і, таким чином, робить його доступним у програмах WinRT та закриває The API '...' cannot be used on the current platform.виняток.

Автори-профілі повинні розміщувати цей атрибут на членах, випущених їхнім профілером, на рамкові збори, якщо вони хочуть отримати доступ до них під WinRT.


1
Так, код, знайдений @Hans, встановлює шукані прапори RuntimeAssembly.InvocableAttributeCtorToken, які викликаються IsNonW8PFrameworkAPI()методами, які ви згадуєте.
Марк Херд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.