Jon*_*ist 13 .net powershell events powershell-4.0
当ref调用带有我订阅的参数的.NET事件时,PowerShell崩溃.
我已将问题减少到以下代码.
.净:
namespace PSEventTest
{
public delegate void BadHandler(ref string str);
public class PSEventTest
{
public event BadHandler BadEvent;
public void InvokeBad()
{
var handler = BadEvent;
if (handler != null)
{
var str = "bad";
handler(ref str);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
电源外壳:
Add-Type -path $PSScriptRoot"\PSEventTest.dll"
$obj = New-Object PSEventTest.PSEventTest
$bad = Register-ObjectEvent -InputObject $obj -EventName BadEvent -Action {
Write-Host "bad!" # it also crashes if this script-block is empty
}
$obj.InvokeBad(); # crash
Run Code Online (Sandbox Code Playgroud)
当我运行PowerShell脚本时,我得到了这个:

如果我按Debug我从Visual Studio得到这个:

该copy exception detail to the clipboard给我这个
System.NullReferenceException was unhandled
Message: An unhandled exception of type 'System.NullReferenceException' occurred in Unknown Module.
Additional information: Object reference not set to an instance of an object.
Run Code Online (Sandbox Code Playgroud)
我想我必须以-Action某种方式将字符串提供给脚本块,但我不知道如何.
PS我正在使用PowerShell 4:
PS C:\Windows\system32> $PSVersionTable.PSVersion
Major Minor Build Revision
----- ----- ----- --------
4 0 -1 -1
Run Code Online (Sandbox Code Playgroud)
我找到了解决这个问题的方法:
.净:
namespace PSEventTest
{
public delegate void BadHandler(ref string str);
public class PSEventTest
{
public event BadHandler BadEvent;
public string InvokeBad()
{
var handler = BadEvent;
if (handler != null)
{
var str = "hi from .NET!";
handler(ref str);
return "from .NET: " + str;
}
return null;
}
}
// as i mention below, this class can be implemented directly in the PS script
public class BadEventSubscriber
{
public void Subscribe(PSEventTest legacyObj, Func<string, string> func)
{
legacyObj.BadEvent += delegate(ref string str)
{
var handler = func;
if (handler != null)
{
var result = handler(str);
str = result;
}
};
}
}
}
Run Code Online (Sandbox Code Playgroud)
电源外壳:
Add-Type -path $PSScriptRoot"\PSEventTest.dll"
$legacyObj = New-Object PSEventTest.PSEventTest
$subscriber = New-Object PSEventTest.BadEventSubscriber
$subscriber.Subscribe($legacyObj, {
param([string]$str)
write-host "from PS: $str"
"hi from PS!"
})
write-host $legacyObj.InvokeBad();
Run Code Online (Sandbox Code Playgroud)
结果:
from PS: hi from .NET!
from .NET: hi from PS!
Run Code Online (Sandbox Code Playgroud)
以前我尝试创建一种(object sender, EventArgs e)处理程序来包装(ref string str)处理程序,但这不起作用,因为PS事件与.NET事件不同步.
传递Func代替使用事件处理程序似乎工作得更好,如上面的代码所示.
我试图概括BadEventSubscriber使用a Expression<Func<object, handler>>来选择Subscribe方法中传递的对象的事件,但是泛型并且Delegate不能很好地一起玩.所以你必须为BadEventSubsciber你想要订阅的每个类和处理程序创建一个-type类(PS不"支持"),但这对我来说是否足够好.
它没有真正的解决方案,因为你仍然需要额外的组件将事件"包装"成一个Func,但作为解决方案,我认为它是可以的.
编辑:
现在我考虑一下,你可以直接在PowerShell中定义订阅者类,就像@RomanKuzmin在我对原始问题的评论中所说的那样.因此,您只需在PowerShell中使用以下内容,而不是附加程序集:
Add-Type @"
using System;
public class BadEventSubscriber
{
public void Subscribe(PSEventTest.PSEventTest legacyObj, Func<string, string> func)
{
legacyObj.BadEvent += delegate(ref string str)
{
var handler = func;
if (handler != null)
{
var result = handler(str);
str = result;
}
};
}
}
"@ -ReferencedAssemblies $PSScriptRoot"\PSEventTest.dll"
$subscriber = New-Object BadEventSubscriber
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
463 次 |
| 最近记录: |