21

我正在尝试将匿名委托(无输入参数,无返回值)的参数传递给函数。

像这样的东西:

private function DoSomething(delegate cmd)
{
     cmd();
}

然后,我想用这个函数以这种方式调用函数:

DoSomething(delegate
{
     Console.WriteLine("Hooah!");
});

我想要这种特定的方式,因为它易于使用的写作风格。

可能的?

4

4 回答 4

37

正是出于这种目的,Microsoft 在 .NET 框架中创建了ActionFunc包装类。这两个类都依赖于匿名函数。如果您不需要返回任何结果,请使用 Action,只需执行匿名函数:

private void DoSomething(Action action)
{
    action();
}

它可以这样使用:

DoSomething(() => 
{
    Console.WriteLine("test");
});

() =>术语是一个lambda 表达式,其含义类似于input with no parameters is calling .... 有关详细说明,请参阅文档。

如果要返回结果,请使用 Func 委托:

private T DoSomething<T>(Func<T> actionWithResult)
{
    return actionWithResult();
}

用法:

Console.WriteLine(DoSomething<int>(() => 
{
    return 100;
}));

两个包装器都具有最多接受 8 个参数的覆盖。

使用 Func 时,最后一个参数始终是返回类型:

// returns a string
Func<string> t = () => { return "test string"; };
// first parameter is of type int, result of type string
Func<int, string> toString = (id) => { return id.ToString(); };
// parameters are of type int and float, result is string
Func<int, float, string> sumToString = (n1, n2) => { return (n1 + n2).ToString(); };

Func 包装器可以直接与类型化参数一起使用:

Func<string, string> up = text => text.ToUpper();
Console.WriteLine(up("test"));

我经常使用 Func 来创建一个通用执行器,该执行器包含在 try/catch 块中,并在发生某些事情时进行记录。这样我减少了重复代码:

private T safeCallWithLog<T>(Func<T> action)
{
    try
    {           
        return action();
    }
    catch (Exception ex)
    {
        Console.WriteLine(String.Format("Oops ...: {0}", ex.Message));
    }
    // return default type if an error occured
    return default(T);
}

用法:

var result = safeCallWithLog<DbEntry>(() =>
            {
                return databaseContext.GetEntryWithId(42);
            });

var id = safeCallWithLog<int>(() =>
                    {
                        return databaseContext.GetIdFor("J.D.");
                    }); 

您仍然可以使用原始委托概念。Action 和 Func 类只是预定义的通用委托方法的包装。

// declare delegate contract
private delegate void output();
// create caller method
private void method(output fun)
{
    fun();
}
// some test functions, that must match exactly the delegate description
// return type and number of arguments
private void test1()
{
    Console.WriteLine("1");
}

private void test2()
{
    Console.WriteLine(DateTime.Now.ToString());
}

// call different methods
method(test1);
method(test2);
// inline call without hard coded method
method(delegate() 
{
    Console.WriteLine("inline");
});
于 2014-02-15T09:41:53.083 回答
3

.NET 有一堆内置的。Action是你想要的没有参数和返回类型的:

private function DoSomething(Action cmd)
{
    cmd();
}

Action<int, int>如果您想要一个带参数但没有返回类型的委托(例如,对于采用两个整数且没有返回的方法),还有一个通用版本的 Action 。

Func并且Predicate(以及那些通用版本)也存在。

于 2014-02-15T09:41:59.183 回答
1

然而,Pasty 描述了大多数可能的解决方案,我只想添加关于关键字委托的内容。

  • 第一种情况是 - 声明新类型:

在示例中,它用于描述输入参数

private function DoSomething(delegate cmd)
{ 
     cmd();
}

但它可用于声明用于包含指向函数的指针的对象类型:

public delegate *returnParameterType* NewTypeName(*inputParamType1* inputParam1, ...)

然后将该NewTypeName用作输入参数的类型:

private function DoSomething(NewTypeName cmd)
    { 
         cmd();  
    }
  • usinf 关键字 'delegate' 的第二种情况就像在您的示例中一样 - 声明匿名方法

    delegate() { Console.WriteLine("Hooah!"); }


但是在那种情况下,必须将此类方法分配给合适的已定义委托,或者将其分配给像 Action 这样的通用委托,因为 Action 不应该具有输出参数

private void delegate Output();
Output func = delegate(){Console.WriteLine("Hooah!");}

或者

Action func1 = delegate(){Console.WriteLine("Hooah!");}
于 2016-03-21T14:29:18.183 回答
0

当然有可能。对于没有返回类型的方法,请使用Actionelse Func<>

public void Function(Action action)
{
    action();
}

并称它为

Function(() => System.Console.WriteLine("test"));

delegate使用 lambdas 而不是关键字是更令人愉快的方式。您甚至可以使用 执行操作action.Invoke(),但在我看来,最好将其称为方法,实际上它就是这样。

于 2014-02-15T09:42:00.840 回答