代码之家  ›  专栏  ›  技术社区  ›  TerryP

如何使函数对方法私有?

  •  4
  • TerryP  · 技术社区  · 14 年前

    我正在研究一个方法,它需要在不同的地方重复一个小操作,但是要重复的代码应该是该方法的私有代码。显而易见的解决方案是嵌套函数。不管我怎么尝试,C编译器都会对我发火。

    大致等于这个perl片段的内容:

    my $method = sub {
        $helper_func = sub { code to encapsulate };
    
        # more code
    
        &$helper( called whenever needed );
    
        # more code
    }
    

    这就是我所说的,也是我在C中试图实现的。

    类中的任何其他方法都不能访问此上下文中的helper函数。用C编写这个结构的最合乎逻辑的方法是这样的:

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

    实际上,让编译器赢得它的保留。

    因为这样的任务 被禁止的 ,就像使用旧的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 回复  |  直到 8 年前
        1
  •  6
  •   Scott Weinstein    14 年前

    如果您在C 3.5或更高版本中,您可以利用lambda和便利委托声明 Func<> Action<> . 例如

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

    你的原因 不能

    var addOne = (ii) => ii +1;
    

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

        2
  •  8
  •   Lasse Skindstad Ebert    14 年前

    你实际上可以用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
    };
    
        3
  •  4
  •   Davy8    14 年前

    如果您显式地键入它,它将工作,即

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

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

        4
  •  2
  •   Russ Cam    14 年前

    我建议你看看 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 做点什么。

    我认为你遇到的问题是你不能使用隐式打字(即使用 var )将lambda表达式赋给变量时。

        5
  •  1
  •   zneak    14 年前

    你不能用 var 关键字与lambda或委托,因为它们都需要额外的上下文信息(委托需要返回类型,lambda需要返回类型和参数类型)。例如, (params) => { code } 语法要求能够推断参数类型并返回工作类型:您通过显式地给它一个类型来实现这一点。

    通用的 System.Action 委托类型(返回 void )能做好你正在尝试的工作:

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

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

        6
  •  0
  •   Rune FS    14 年前

    这取决于你对隐藏的定义。

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

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

    feals类似于在编写常规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;
            }
        }
    

    因此,如果您真的想从一个“hidding”之外获得方法,那么您可以通过反射来实现这一点,为存储委托的字段生成的实际名称在clr上下文中有效的c bul中是非法的,但这是唯一妨碍将委托用作存储在字段中的常规委托的方法(也就是说,如果您名字::)

        7
  •  -1
  •   Morfildur    14 年前

    其实很简单。由于该方法似乎比当前类有另一个职责(否则为什么要隐藏此方法),请将该方法移入它自己的类中,并将希望私有的部分移入新类中的私有方法中。