Provide a .NET method as a delegate callback

2019-01-23 04:31发布

What is the syntax to pass .NET method as a delegate callback to a .NET object in PowerShell.

For example:

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)

This doesn't work.

5条回答
Deceive 欺骗
2楼-- · 2019-01-23 04:45

Via @oising on Twitter:

@adamdriscoll you're spoiled by the c# compiler's delegate inferencing. You need to new up that action explicitly, old school styley.

$method = [Class2].GetMethod("Callback") 
$delegate = [System.Delegate]::CreateDelegate([System.Action[Object]], $null, $method
[Class1]::MyMethod($delegate)
查看更多
贼婆χ
3楼-- · 2019-01-23 04:46

The type of [Class2]::Callback is System.Management.Automation.PSMethod which apparently cannot be converted by the core to the required delegate.

I am not sure that this is the best way of solving the task (I have not seen any kind of official documentation about this) but the code below works for me in this example case and other similar cases in my practice:

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

The core is able to convert our script block { [Class2]::Callback($args[0]) } to the required delegate.

P.S. Though not directly related to the question but here is yet another working example of this technique: using script blocks as match evaluator delegates in regular expressions: How to sort by file name the same way Windows Explorer does?

查看更多
够拽才男人
4楼-- · 2019-01-23 04:52
$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')))
查看更多
\"骚年 ilove
5楼-- · 2019-01-23 04:59

Working code via Adam's and Oisin's chat.

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)
查看更多
趁早两清
6楼-- · 2019-01-23 05:11

I am not an expert at C#, but after reading a couple articles it seems that you are trying to use generic delegates. Your Callback method is not a generic delegate, it isn't even a delegate.

I think this is what you need to do:

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)
查看更多
登录 后发表回答