【问题标题】:Provide a .NET method as a delegate callback提供 .NET 方法作为委托回调
【发布时间】:2012-09-02 08:01:15
【问题描述】:

在 PowerShell 中将 .NET 方法作为委托回调传递给 .NET 对象的语法是什么。

例如:

C#:

public class Class1
{
    public static void MyMethod(Action<object> obj)
    {
         obj("Hey!");
    }
}

public class Class2
{
    public static void Callback(object obj)
    {
         Console.Writeline(obj.ToString());
    }
}

PowerShell:

[Class1]::MyMethod([Class2]::Callback)

这不起作用。

【问题讨论】:

标签: c# .net powershell delegates powershell-2.0


【解决方案1】:

通过 Adam 和 Oisin 聊天的工作代码。

Add-Type -Language CSharpVersion3 -TypeDefinition @"
using System;

public class Class1
{
    public static void MyMethod(Action<object> obj)
    {
         obj("Hey!");
    }
}

public class Class2
{
    public static void Callback(object obj)
    {
         Console.WriteLine(obj.ToString());
    }
}
"@

$method   = [Class2].GetMethod("Callback") 
$delegate = [System.Delegate]::CreateDelegate([System.Action[Object]], $null, $method)

[Class1]::MyMethod($delegate)

【讨论】:

    【解决方案2】:
    $code = @'
    using System;
    public class Class1
    {    
        public static void MyMethod(Action<object> obj)    
        {
            obj("Hey!");    
        }
    }
    public class Class2
    {    
        public static void Callback(object obj)    
        {         
            Console.WriteLine(obj.ToString());    
        }
    }
    '@
    
    Add-Type -TypeDefinition $code -Language CSharpVersion3
    
    [class1]::mymethod([system.action]::CreateDelegate('System.Action[Object]', [class2].getmethod('Callback')))
    

    【讨论】:

      【解决方案3】:

      通过@oising on Twitter

      @adamdriscoll 你被 c# 宠坏了 编译器的委托推理。你 需要明确地更新该操作, 老派风格。

      $method = [Class2].GetMethod("Callback") 
      $delegate = [System.Delegate]::CreateDelegate([System.Action[Object]], $null, $method
      [Class1]::MyMethod($delegate)
      

      【讨论】:

        【解决方案4】:

        [Class2]::Callback 的类型是 System.Management.Automation.PSMethod,它显然无法由核心转换为所需的委托。

        我不确定这是解决任务的最佳方法(我没有看到任何关于此的官方文档),但下面的代码在这个示例案例和我实践中的其他类似案例中适用于我:

        [Class1]::MyMethod({ [Class2]::Callback($args[0]) })
        

        核心能够将我们的脚本块{ [Class2]::Callback($args[0]) } 转换为所需的委托。

        附:虽然与问题没有直接关系,但这里是该技术的另一个工作示例:在正则表达式中使用脚本块作为匹配评估器委托: How to sort by file name the same way Windows Explorer does?

        【讨论】:

        • 感谢您的回复。这里的问题是我试图避免将调用包装在脚本块中,因为我正在做一些古怪的线程处理。这确实有效,但在我的情况下不起作用。我正在寻找一种直接执行此操作的方法。
        • 我真的很感兴趣为什么它不能与你的“古怪线程的东西”一起工作。什么是错误/问题?是不是类似于“没有运行空间......”?
        • 是的。我需要在新线程中调用某些东西,但不能调用脚本块,因为该线程中没有默认运行空间。我正在写一篇关于它的博客文章,所以今晚晚些时候会有更多关于它的细节。
        • 是的,这确实是问题所在。在某些情况下,如果启动该线程的 C# 代码可以识别 PowerShell,那么您可以在该线程中执行的第一件事是 Runspace.DefaultRunspace = &lt;runspace were the script is invoked&gt;;。这个技巧在我的自定义主机中运行良好,带有一些线程。
        【解决方案5】:

        我不是 C# 方面的专家,但在阅读了几篇文章后,您似乎正在尝试使用泛型委托。您的 Callback 方法不是通用委托,甚至不是委托。

        我认为这是你需要做的:

        C#

        public class Class1
        {
            public static void MyMethod(Action<object> obj)
            {
                 obj("Hey!");
            }
        }
        
        public class Class2
        {
            public Action<object> CallBack = obj => Console.WriteLine(obj.ToString());
        }
        

        Powershell:

        [Class1]::MyMethod([Class2]::Callback)
        

        【讨论】:

        • 感谢您的回复,但在 C# 中,回调方法确实与委托的签名匹配。您的定义是一个 lambda 函数的示例,如果您要使用 Reflector 之类的东西进行反编译,它也会非常接近“回调”的方法定义
        • 如何为 PSMethod/PSScriptMethod 创建委托? $o = new-object psobject; $o | Add-Member -MemberType ScriptMethod -Name "test" -Value { return "some object" }$o.test(不带括号会告诉我这是一个 PSScriptMethod,并且有一个基于 PSMethod)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多