C#自引用一个方法

时间:2015-11-20 13:47:16

标签: c#

我可以在方法中自引用,而不使用方法名称(出于代码维护原因,这可能会导致未来的错误)

void SelfRef(string _Input){

    if (_Input == "route1"){

        //route1 calls route 2

        SelfRef("route2"); //call self


    }else if (_Input == "route2"){

        //route2 ends
    }
}

我想不再写“SelfRef”这个词,让这个功能免受未来变化的影响?

9 个答案:

答案 0 :(得分:7)

是的,有可能:

void Foo(int bar)
{
    Console.WriteLine(bar);
    if(bar < 10)
        MethodBase.GetCurrentMethod().Invoke(this, new object[] {++bar});
    else
        Console.WriteLine("Finished");
}

但是请永远不要使用这样的代码(它很难看,它很慢,很难理解,如果方法是内联的,它将不起作用)。

由于您可能使用像Visual Studio这样的IDE,因此重命名方法永远不应成为问题;即使您手动重命名该方法,您可能会遇到编译时错误。

答案 1 :(得分:6)

  

我不想写下#34; SelfRef&#34;再次使功能免受未来变化的影响?

正如其他人所说,如果您打算重命名方法,则应该只使用重命名工具。

但是,制作一个不引用函数名称的递归函数是一个有趣的挑战。这是一种方法:

delegate Action<A> Recursive<A>(Recursive<A> r);

static Action<A> AnonymousRecursion<A>(Func<Action<A>, Action<A>> f)
{
    Recursive<A> rec = r => a => { f(r(r))(a); };
    return rec(rec);
} 

Action<string> SelfRef = AnonymousRecursion<string>(
    f => 
        input => 
        {  
            if (input == "route1")
                f("route2");
            // and so on
        });

注意字段SelfRef如何在其身体中引用SelfRef,但递归非常简单;您只需递归f而不是SelfRef

但是我告诉你,这个代码比简单地编写一个简单的递归方法更难以理解和维护。

答案 2 :(得分:2)

现在让我们清楚地说明“自我引用”的技术术语是递归。让我们开始研究这个问题。

您希望编写递归方法,但由于可维护性原因,不希望“提及”方法名称。当我看到这个时,我就像是,“你在用什么编辑器?”。可维护性原因?你的意思是当你更改代码中断方法的名称时?

使用IDE可以轻松解决这些问题。我建议你使用Visual Studio Community 2015.它是免费的,并提供广泛的功能。如果要重命名方法,请执行以下操作:

  1. 右键单击方法名称。

  2. 在上下文菜单中选择“重命名”

  3. 输入您想要的名称。

  4. 按Enter键

  5. 你会神奇地看到,所有对该方法的引用都改变了它们的名字!

    所以你不需要将整个递归方法转换成循环或其他东西。你只需要使用正确的编辑器!

答案 3 :(得分:1)

您可以像这样创建扩展程序

public static void RecursivelyCall(this object thisObject, object [] param,  [System.Runtime.CompilerServices.CallerMemberName] string methodName = "")
{
    Type thisType = thisObject.GetType();
    MethodInfo theMethod = thisType.GetMethod(methodName);
    theMethod.Invoke(thisObject, param);
}

public static void RecursivelyCall(this object thisObject, object param, [System.Runtime.CompilerServices.CallerMemberName] string methodName = "")
{
    Type thisType = thisObject.GetType();
    MethodInfo theMethod = thisType.GetMethod(methodName);
    theMethod.Invoke(thisObject, new object[] {param});
}

所以你可以用它来进行递归调用

private void Rec(string a)
{
    this.RecursivelyCall(a);
}

但是,说实话,我不认为这是个好主意,因为

  

功能免疫未来的变化

不值得丢失代码可读性。

答案 4 :(得分:0)

自我引用(可能是通过反射)和递归看起来很长,当一个循环就足够了:

void SelfRef(string _Input){
    while(true)
    {
        if (_Input == "route1"){

            _Input = "route2"
            continue;

        }else if (_Input == "route2"){

            //route2 ends
            break;
        }
        //break?
    }
}

答案 5 :(得分:0)

C#中没有构造来引用您所使用的方法并使用不同的参数调用它。您可以检查调用堆栈以找到方法 name 并使用反射来调用它,但它似乎毫无意义。

您将“免疫”的唯一类型的错误是重命名方法。在这种情况下,构建将失败,您很快就会发现出现问题。

答案 6 :(得分:0)

可以使用MethodBase.GetCurrentMethod()进行反射,这是我所知道的最快方式。当然比使用Stacktraces更快。
您可以按如下方式更改代码:

void SelfRef(string _Input){

    if (_Input == "route1"){

        //route1 calls route 2

        MethodBase.GetCurrentMethod().Invoke(this,new []{"route2"}); //call self

    }else if (_Input == "route2"){

        //route2 ends
    }
}

不要忘记using System.Reflection名称空间。

答案 7 :(得分:0)

  

您正在使用递归,而不是自我引用

调用自身的函数(方法)被称为递归函数,这个概念称为递归。你本质上拥有的是一个名为SelfRef的递归函数,它将一个字符串作为参数。如果参数等于"route1"这是一个字符串,它会自行调用。

  

方法引用将方法传递给另一个方法

方法引用(在其他语言中调用)在C#中称为委托,用于将函数本身传递给另一个函数。这主要用于实现回调,即事件处理程序。例如,您可能会在事件中看到此代码。

public class DelegateExample
{
    public delegate void MyDelegate();

    public void PrintMessage(MyDelegate d)
    {
        d();
    }

    public void PrintHello()
    {
        Console.WriteLine("Hello.");
    }

    public void PrintWorld()
    {
        Console.WriteLine("World.");
    }

    public static void Main(string[] args)
    {
        PrintDelegate(new MyDelegate(PrintHello));
        PrintDelegate(new MyDelegate(PrintWorld));
    }
}

在那里,您看到,您正在将一个函数作为代理传递。

  

如果您知道哪些路线已经可用,请使用枚举

绝不使用字符串在对象之间进行通信或使用程序,只使用它们与用户进行交互。在编写程序时最好的选择(如果路由是预先知道的),则使用枚举来实现此目的。

答案 8 :(得分:0)

按名称调用函数不会导致代码维护问题。

当有人重命名时,所有现代开发环境(例如Visual Studio)都会自动更新该功能名称的每次使用。

如果您希望使该功能免受未来更改的影响,请保留源代码。