【问题标题】:Null all delegates using reflections使用反射为空所有代表
【发布时间】:2013-07-24 21:19:25
【问题描述】:

我有一些代码:

private static st_createInstance        createInstance;
private static st_destroyInstance       destroyInstance;
private static st_getVersionId          getVersionId;
private static st_getVersionString2     getVersionString2;

//...

[UnmanagedFunctionPointer (CallingConvention.StdCall)]
private delegate IntPtr st_createInstance ();

[UnmanagedFunctionPointer (CallingConvention.StdCall)]
private delegate void st_destroyInstance (IntPtr pHandle);

//...

现在如何使用反射使所有这些委托为空? (Idk 如何将 Fields 与委托类型进行比较)。

编辑:我想以简单的方式将它们全部归零,例如 foreach 循环。不想指定每个字段名称。

【问题讨论】:

  • (1) 将它们嵌套在 struct(值类)中。您可以只有一个静态实例。 (2) 将刚刚使用new创建的新实例分配给静态成员变量。

标签: c# reflection delegates


【解决方案1】:

如果type 是委托字段所在的对象类型,请尝试以下操作:

var fields = type.GetFields(BindingFlags.Static | BindingFlags.NonPublic);

fields = fields.Where(f => f.FieldType.BaseType == typeof(System.MulticastDelegate));

foreach (FieldInfo fi in fields)
{
    fi.SetValue(null, null);
}

SetValue中的第一个null表示它是一个静态字段,第二个用于将字段的值设置为null

【讨论】:

  • 看看我的问题,我现在解释得更好了。
  • 无法投射。所以我将“fields = fields.Where ...”行修改为“var newFields = fields.Where ...”。它现在工作正常,但还有一个我不明白的附加字段:System.Func`2[[System.Reflection.FieldInfo, mscorlib, Version=4.0.0.0, Culture=n 中性, PublicKeyToken=b77a5c561934e089],[System.布尔值,mscorlib,版本 = 4.0。 0.0,文化=中性,PublicKeyToken=b77a5c561934e089]]
  • 我在发布后不久更新了我的新答案 - 确保您拥有 f => f.FieldType.BaseType 而不仅仅是 f => f.BaseType
【解决方案2】:

这强烈暗示了一个 XY 问题。当 OP 没有解释为什么他需要做某事时,这总是一个问题。当您尝试完成 pinvoke marshaller 使用 [DllImport] 属性完成的工作时,您会编写此类代码。

如果这完全正确,那么请注意,将这些委托对象设置回 null 没有什么意义,即使它们是静态的。它们实际上指的是 thunk,即在非托管代码和托管代码之间编组的一小段自动生成的代码。通常它只不过是一条简单的 JMP 指令,当需要重新调整堆栈帧时,它会变得更加复杂。

委托对象本身需要一小部分 GC 堆,只有 32 个字节。您将希望避免编写使用反射来摆脱约 36 个字节的代码,在时间或空间上都没有回报。代码已经比你释放的内存大了。更不用说真正的成本,你维护这段代码。

考虑去掉初始化这些委托的代码。几乎从不需要,pinvoke marshaller 已经非常擅长自己做这件事。您只需要帮助它找出在哪里可以找到 DLL,有很多比使用 LoadLibrary() 更好的方法。以this answer 为例。

【讨论】:

  • documentation says otherwise thunk do 被释放。 “收集委托时,将删除非托管编组代码。”
  • 天哪,看起来好复杂。我明天会仔细阅读它,因为我现在太累了。当 GetDelegateForFunctionPointer 在一个或多个调用上失败时(例如,如果我加载的不是我想要的这个 DLL 文件),我只想让这些委托为空。
  • 如果您无法加载 DLL,那么您一开始就无法初始化委托对象。改进您的错误处理,永远不要忽略 LoadLibrary 和 GetProcAddress 的返回值。
  • 场景:1) 加载错误的 dll 文件 2) 尝试使用 GetDelegateForFunctionPointer 创建委托。 3)如果一些委托是空的,有错误的dll库,所以我可以抛出异常之类的。 A)可以使用反射来检查所有这些代表不为空吗? B)如果库错了,那么我只需要保留那些静态字段,因为它们是witohut让它们为空?
  • 当加载了错误的 DLL 时,您真正希望发生什么?试图将它们设置回 null 只是掩盖了问题。 NullReferenceException比一个好的 Win32Exception 更容易诊断,当您发现芯片已关闭时可以抛出该异常。我已经解释了为什么将错误的委托对象引用设置回 null 没有任何意义。您可以恢复的唯一方法是将它们设置为 good 正确 DLL 的委托对象。你有大约 0.01% 的几率实现这一目标。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-20
  • 2017-05-19
  • 2010-12-05
  • 2015-06-17
  • 2017-11-23
  • 1970-01-01
  • 2013-06-25
相关资源
最近更新 更多