【问题标题】:What is the __DynamicallyInvokable attribute for?__DynamicallyInvokable 属性有什么用?
【发布时间】:2023-04-11 08:03:01
【问题描述】:

查看 DotPeek 中的 System.Linq.Enumerable,我注意到某些方法带有 [__DynamicallyInvokable] 属性。

这个属性有什么作用?是 DotPeek 添加的东西还是起到了其他作用,可能会告知编译器如何最好地优化方法?

【问题讨论】:

  • String.Empty 也有这个,顺便说一句。
  • IReadOnlyCollection<T> 也是如此。
  • 还有 System.ServiceModel v3BasicHttpBinding.TextEncoding(在 V4 中已升级到新的基类并变为 HttpBindingBase.TextEncoding
  • 它也用于系统枚举中的整数值,如 DayOfWeek
  • 一旦我有一个案例,当具有此属性的方法被内联到生成的程序集中(DateTime.AddYears,.Net 4.5)

标签: c# dynamic-invoke


【解决方案1】:

它没有记录,但它看起来像是 .NET 4.5 中的优化之一。它似乎用于启动反射类型信息缓存,从而使常见框架类型上的后续反射代码运行得更快。 System.Reflection.Assembly.cs,RuntimeAssembly.Flags 属性的Reference Source 中有注释:

 // 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。

【讨论】:

  • 看起来存储的值被用于检查 API 是否在 WP8 上可用。
  • +1 请参阅我对 OP 的 Q 的评论 - CLR 似乎基于此进行欺骗的一种情况是处理方法的“轻微”移动(例如,向下一层到新的基础类)统一下
  • 这是 [TypeForwardTo] 技巧,完全不同。
  • @HansPassant 有趣 - 听起来我很可能是错的,所以......没想过检查原始组件/类型。底线是,在 4.5 上,引用的 property(不是类型)相对于 3.5 上的位置(技术上,System.ServiceModel 3.0)移动了。我曾认为 mscorlib 引用的统一正在发挥作用,但无论如何我的具体问题仍有很多事情要做 - 将在适当的时候向我的 cmets 报告和/或删除任何误导性的语气......跨度>
  • @HansPassant 从进一步的研究中......看不到任何关于类型转发所做的事情,而不是转发类型,所以在这一点上,我请求与 something fully different 位有所不同。起作用的力量很简单,当您有一个引用System.ServiceModel v3 的CLR2 程序集时,在CLR4 下加载它会自动升级到System.ServiceModel v4。有趣的是,.NET 4.5 对System.ServiceModel 的位进行了就地更新,将其放入 下的新基类并将属性向下移动了一个级别
【解决方案2】:

我发现它用于Runtime*Info.IsNonW8PFrameworkAPI() 内部方法套件。将此属性置于成员上会使 IsNonW8PFrameworkAPI() 为其返回 false,从而使该成员在 WinRT 应用程序中可用并关闭 The API '...' cannot be used on the current platform. 异常。

如果探查器编写者想要在 WinRT 下访问这些成员,则应将此属性放在其探查器发出的成员上并放入框架程序集中。

【讨论】:

  • 是的,@Hans 找到的代码设置了RuntimeAssembly.InvocableAttributeCtorToken 查找的标志,由您提到的IsNonW8PFrameworkAPI() 方法调用。
猜你喜欢
  • 2010-11-12
  • 2013-08-08
  • 2014-09-12
  • 1970-01-01
  • 2012-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多