如何将函数设为私有方法?

时间:2010-08-01 15:59:11

标签: c# lambda anonymous-function encapsulation

我正在研究一种需要在不同位置重复小操作的方法,但要重复的代码应该是该方法的私有代码。显而易见的解决方案是嵌套函数。无论我尝试了什么,C#编译器对我来说都是barfs。

大致等于这个Perl片段:

my $method = sub {
    $helper_func = sub { code to encapsulate };

    # more code

    &$helper( called whenever needed );

    # more code
}
我正在谈论的是什么,以及我在C#中想要实现的目标。

类中没有其他方法可以在此上下文中访问辅助函数。在C#中编写这个构造的最合理的方法,就像在我看来那样:

var helper = (/* parameter names */) => { /* code to encapsulate */ };

实际上让编译器获得了保持。

由于这样的赋值是 forbidden ,因为使用旧的delegate(){}语法代替lambda,因此在方法中声明委托类型 - 实际上是csc允许我写,但是:

private delegate /* return type */ Helper(/* parameters */);
private /* return type */ method(/* parameters */) {

    Helper helper = (/* parameter names */) => { 
        /* code to encapsulate */
    };

    // more code

    helper( /* called whenever needed */ );

    // more code
}

对于不复制和粘贴一大堆代码并手动编辑参数,这一切都很好,但它会将私有委托类型泄漏给类的其余部分而不是将其保密。这首先打败了目的。对参数使用goto语句和局部变量可以在此上下文中更好地封装“helper”,而不会牺牲代码重用。如果我想通过寄存器传递参数来模拟函数调用,我想宁愿使用汇编程序。我没有找到一种可接受的重构代码的方法来完全避免这个问题。

那么,甚至可以强迫这个Common Object Oriented Language服从吗?

7 个答案:

答案 0 :(得分:8)

您实际上可以在C#中执行此操作。

Func<T1, T2, ..., TReturn> myFunc = (a, b, ...) =>
{
  //code that return type TReturn
};


如果需要匿名方法返回类型void使用Action而不是Func:

Action<T1, T2, ...> myAction = (a, b, ...) =>
{
  //code that doesn't return anything
};

答案 1 :(得分:6)

如果您使用的是C#3.5或更高版本,则可以利用lambdas和便捷委托声明Func<>Action<>。所以例如

void DoSomething()
{
  Func<int,int> addOne = (ii) => ii +1;
  var two = addOne(1);
}

无法

的原因
var addOne = (ii) => ii +1;

是因为Homoiconicity,lambda可以解释为两个不同的结构,一个委托和一个表达式树。因此需要在声明中明确。

答案 2 :(得分:4)

如果您明确键入它,它将起作用,即

Action<paramType1, paramType2> helperAction = (/* parameter names */) => { /* code to encapsulate */ };
Func<paramType1, paramType2, returnType> helperFunction = (/* parameter names */) => { /* code to encapsulate */ };

var不起作用的原因是lambda表达式可以计算为多个类型(我相信委托或表达式树,但不引用我),在这种情况下编译器是无法推断出这意味着什么。

答案 3 :(得分:2)

我建议您查看 Action<T> Func<TResult> 代表及其超载情况。你可以做这样的事情

static void Main(string[] args)
{
    SomeMethod();
}

private static void SomeMethod()
{
    Action<int> action = (num) => Console.WriteLine(num);

    Enumerable.Range(1,10).ToList().ForEach(action);

    Console.ReadKey();
} 

此处SomeMethod是私有的,并且有一个本地Action<int> delgate,需要int并对其执行某些操作。

我认为您遇到的问题是在为变量分配lambda表达式时不能使用隐式类型(即使用var)。

答案 4 :(得分:1)

您不能将var关键字与lambdas或委托一起使用,因为它们都需要其他上下文信息(委托需要返回类型,而lambdas需要返回类型和参数类型)。例如,(params) => { code }语法需要能够推断参数类型和返回类型才能工作:您可以通过显式赋予它类型来完成此操作。

通用System.Action委托类型(返回void)可以很好地处理您正在尝试的内容:

Action<ArgumentType1, ArgumentType2, ...> myDelegate = (params) => { code };

否则,还有System.Func,它有一个返回类型,必须作为最后一个通用参数传递。

答案 5 :(得分:0)

这取决于你的隐藏定义。

func / action解决方案(就像Scott建议的那样)

void DoSomething()
{
  Func<int,int> addOne = (ii) => ii +1;
  var two = addOne(1);
}

在编写常规C#代码时隐藏方法定义的麻烦但是在查看IL等价物时

//This is pseudo code but comes close at the important parts
public class Class1
    {
        //The actual type is different from this
        private static Func<int, int> myMethod = AnonymousFunction; 

        public void f()
        {
            myMethod(0);
        }

        private static int AnonymousFunction(int i)
        {
            return 1;
        }
    }

因此,如果您真的想从“隐藏”之外的方法获取方法,则可以使用反射执行此操作为存储代理的字段生成的实际名称在CLR上下文中的C#bul有效,但这是唯一阻碍使用委托作为存储在字段中的常规委托的方式(即如果你指出名称:))

答案 6 :(得分:-1)

实际上很简单。由于Method似乎还有另一个责任,而不是你当前的Class(为什么你会隐藏这个方法)将你的方法移动到它自己的Class中,你想要私有的部分放入新类的私有方法中。