C#:通过引用将附加参数传递给委托
C#: Pass additional argument to delegate by reference
我目前正在尝试大力优化程序的运行时间,但偶然发现了以下问题。
问题
有时我必须从 user32.dll
调用 EnumWindows
(参见 Microsoft Docs),定义如下所示:
internal static class NativeMethods
{
public delegate bool EnumWindowsProc(IntPtr hWnd, int lParam);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumWindows(EnumWindowsProc enumFunc, IntPtr lParam);
//...
}
如您所见,我传递了一个委托来对每个 window 做一些事情。
我这样调用这个方法:
NativeMethods.EnumWindows(GetVisibleWindowDelegate, IntPtr.Zero);
和
private bool GetVisibleWindowDelegate(IntPtr windowHandle, int _)
注意:我没有在委托中使用 int
参数,因此没有使用名称。
这很好用。现在进行优化:我必须访问和存储几个 List<IntPtr>
和 IDictionary<int, Rectangle>
类型的动态列表,这些动态列表包含在一个名为 RuntimeInformation
的对象中,跨多个 classes.
从这个 RuntimeInformation 对象来回复制值会在我的硬件上为每个方法调用占用大约 20 毫秒的宝贵运行时间。这就是为什么我想通过引用传递这个对象,但是我无法将引用获取到我的 GetVisibleWindowDelegate
.
接近
我无法更改委托类型,因为我无法控制调用它。
如果我尝试这样调用 EnumWindows
:
NativeMethods.EnumWindows(
(windowHandle, _) => GetVisibleWindowDelegate(windowHandle, ref runtimeInformation),
IntPtr.Zero
);
我收到错误
Error CS1628 Cannot use ref, out, or in parameter 'runtimeInformation' inside an anonymous method, lambda expression, query expression, or local function
据我所知不存在 class 属性 参考文献。
问题
如何将我的 RuntimeInformation
引用到我用作委托的函数中?这种方法有替代方法吗?
解决方案应该具有高性能(第一优先级)并且可维护。
你可以使用 GCHandle
for this. In fact the docs for GCHandle.Alloc
有一个例子来说明你正在尝试做什么。
private static bool GetVisibleWindowDelegate(IntPtr windowHandle, IntPtr lparam)
{
var handle = GCHandle.FromIntPtr(lparam);
var runtimeInformation = (RuntimeInformation)handle.Target;
// ...
}
RuntimeInformation runtimeInformation = ...
var handle = GCHandle.Alloc(runtimeInformation);
try
{
var callback = new EnumWindowsProc(GetVisibleWindowDelegate);
NativeMethods.EnumWindows(callback, GCHandle.ToIntPtr(handle));
}
finally
{
handle.Free();
}
我目前正在尝试大力优化程序的运行时间,但偶然发现了以下问题。
问题
有时我必须从 user32.dll
调用 EnumWindows
(参见 Microsoft Docs),定义如下所示:
internal static class NativeMethods
{
public delegate bool EnumWindowsProc(IntPtr hWnd, int lParam);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumWindows(EnumWindowsProc enumFunc, IntPtr lParam);
//...
}
如您所见,我传递了一个委托来对每个 window 做一些事情。
我这样调用这个方法:
NativeMethods.EnumWindows(GetVisibleWindowDelegate, IntPtr.Zero);
和
private bool GetVisibleWindowDelegate(IntPtr windowHandle, int _)
注意:我没有在委托中使用 int
参数,因此没有使用名称。
这很好用。现在进行优化:我必须访问和存储几个 List<IntPtr>
和 IDictionary<int, Rectangle>
类型的动态列表,这些动态列表包含在一个名为 RuntimeInformation
的对象中,跨多个 classes.
从这个 RuntimeInformation 对象来回复制值会在我的硬件上为每个方法调用占用大约 20 毫秒的宝贵运行时间。这就是为什么我想通过引用传递这个对象,但是我无法将引用获取到我的 GetVisibleWindowDelegate
.
接近
我无法更改委托类型,因为我无法控制调用它。
如果我尝试这样调用 EnumWindows
:
NativeMethods.EnumWindows(
(windowHandle, _) => GetVisibleWindowDelegate(windowHandle, ref runtimeInformation),
IntPtr.Zero
);
我收到错误
Error CS1628 Cannot use ref, out, or in parameter 'runtimeInformation' inside an anonymous method, lambda expression, query expression, or local function
据我所知不存在 class 属性 参考文献。
问题
如何将我的 RuntimeInformation
引用到我用作委托的函数中?这种方法有替代方法吗?
解决方案应该具有高性能(第一优先级)并且可维护。
你可以使用 GCHandle
for this. In fact the docs for GCHandle.Alloc
有一个例子来说明你正在尝试做什么。
private static bool GetVisibleWindowDelegate(IntPtr windowHandle, IntPtr lparam)
{
var handle = GCHandle.FromIntPtr(lparam);
var runtimeInformation = (RuntimeInformation)handle.Target;
// ...
}
RuntimeInformation runtimeInformation = ...
var handle = GCHandle.Alloc(runtimeInformation);
try
{
var callback = new EnumWindowsProc(GetVisibleWindowDelegate);
NativeMethods.EnumWindows(callback, GCHandle.ToIntPtr(handle));
}
finally
{
handle.Free();
}