Ответ 1
Я нашел рабочий процесс для этой проблемы:
.NET:
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;
}
};
}
}
}
PowerShell:
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();
Результат:
from PS: hi from .NET!
from .NET: hi from PS!
Раньше я пытался создать тип обработчика (object sender, EventArgs e)
для переноса обработчика (ref string str)
, но это не сработало, потому что событие PS было уволено из синхронизации с событием .NET.
Передача Func
вместо использования обработчика событий, похоже, работает намного лучше, как показано в приведенном выше коде.
Я попытался обобщить BadEventSubscriber
, чтобы использовать Expression<Func<object, handler>>
для выбора события из переданного объекта в методе Subscribe
, но generics и Delegate
не работают хорошо. Таким образом, вам нужно будет создать класс BadEventSubsciber
-type для каждого класса и обработчика, на который вы хотели бы подписаться (что PS не поддерживает), но для меня это сейчас достаточно хорошо.
Это не настоящее решение, так как вам все равно понадобится дополнительная сборка для "обертывания" события в Func
, но как work-around, я думаю, что все в порядке.
EDIT:
Теперь, когда я думаю об этом, вы можете просто определить класс подписчика непосредственно в PowerShell, как @RomanKuzmin сказал в своем comment к моему первоначальному вопросу. Поэтому вместо дополнительной сборки у вас просто есть следующее в 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