C# 获取c中函数的名称#

C# 获取c中函数的名称#,c#,unity3d,C#,Unity3d,在Unity中,当使用协程或InvokeRepeating时,必须给出一个包含要调用的函数名的字符串。虽然如果您更改该函数的名称,这是一件痛苦的事情,因为您必须记住更改使用它的协同程序。有没有更干净的方法 现在看起来是这样的: InvokeRepeating ("SendChangedValues", SEND_RATE, SEND_RATE); 虽然有这样的东西会很好 InvokeRepeating (SendChangedValues.Name(), SEND_RATE, SEND_RAT

在Unity中,当使用协程或InvokeRepeating时,必须给出一个包含要调用的函数名的字符串。虽然如果您更改该函数的名称,这是一件痛苦的事情,因为您必须记住更改使用它的协同程序。有没有更干净的方法

现在看起来是这样的:

InvokeRepeating ("SendChangedValues", SEND_RATE, SEND_RATE);
虽然有这样的东西会很好

InvokeRepeating (SendChangedValues.Name(), SEND_RATE, SEND_RATE); //or
InvokeRepeating (functions.GetName(SendChangedValues), SEND_RATE, SEND_RATE);
这在c#中可能吗?或者,当我在不更改字符串的情况下更改函数名时,确保收到错误/警告

编辑1:我能想到的最干净的事情是用函数名生成一个常量字符串,并将它放在函数本身之前。所以很难忘记更改字符串,因为它就在它上面,我也只需要更改一个常量字符串就可以更改所有的协程


谢谢

我理解你的问题,我没有解决这个问题的黄金方案

可能会有帮助的是,使用lambda表达式作为一种方式来解决这个问题


它描述了一种通过传递将作为
MethodCallExpression
计算的
表达式来计算方法名的方法。您可以从中提取相关信息。

我记得在另一个上下文中做过类似的事情。事情是这样的:

InvokeRepeating ("SendChangedValues", SEND_RATE, SEND_RATE);
您声明了自己的方法,该方法使用原始方法:

public static void MyInvokeRepeating<T>(Func<T> method)
{
    InvokeRepeating(method.Method.Name, SEND_RATE, SEND_RATE);
}

更好的是,创建一个扩展方法。

在处理方法(不是属性或字段)时,不需要lambda表达式


您可以编写一个接受委托的
invokereepeating
包装器。在代理上调用
GetInvocationList
,以获取名为的
MethodInfo

ahhh。。如果它是下一个C#版本,您可以使用操作符的名称

现在,这对你的事业有帮助吗

private static string GetFunctionName(Action method)
{
 return method.Method.Name;
}
调用时使用:

string methodName = GetFunctionName(SendChangedValues);
您可能需要探索不同的委托类型。。行动、职能等


上面提到的唯一问题是,对于每个方法签名,您可能需要定义正确的签名/重载来获取名称。

如果您没有传递额外的参数,协同程序确实允许它。第一个示例显示了一个重载,其签名为
Coroutine startcroutine(IEnumerator例程)


调用重复
,不幸的是,没有相同的重载。您应该能够在那里使用反射来完成它,尽管在其他一些答案中提到了这一点。

您可以通过静态反射来完成这一点(至少在.NET 4中,可能在3.5及以下版本中)

//这个
InvokeRepeating(((MethodCallExpression)((Expression)(x=>x.ToString())).Body).Method.Name,SEND\u RATE,SEND\u RATE);
//与
调用重复(“ToString”,发送速率,发送速率);

您只需要知道正在调用的函数的签名,并相应地替换上例中的操作。

我在我的代码库中使用以下内容,外推用于调用重复

public delegate void Task();

public static class MonoBehaviourExtensions {
  public static void InvokeLater(
    this MonoBehaviour b,
    float time,
    Task task)
  {
    b.Invoke(task.Method.Name, time);
  }
}
像这样使用它

MyInvokeRepeating(someObject.SomeFunction);
public class MyBehaviour : MonoBehaviour {
  void Start(){
    this.InvokeLater(1f, DoSomething1SecondLater);
  }

  public void DoSomething1SecondLater(){
    Debug.Log("Welcome to the future");
  }
}

从现有的协同程序中创建一个
enum

public enum MyCoroutines
{ 
Coroutine1,
Coroutine2
}

InvokeRepeating(MyCoroutines.Coroutine1.ToString(), x, y);

这样您就不会有拼写错误的危险,而且您可以很容易地找到并替换它们。它还非常适合播放声音和动画。

以下是我对这一问题的看法,因为我最近在UnityEvent侦听器的上下文中偶然发现了这个问题,UnityEvent侦听器也存储了,只能通过方法的名称检索。我的方法在处理具有不同签名的事件处理程序时更有意义,但它也适用于任何操作和调用

public void Start()
{
援引(
methodName:GetMethodName((System.Action)分解),
时间:1f);
援引(
methodName:GetMethodName((System.Action)HandleMyNumber),
时间:2f);
}
公共静态字符串GetMethodName(System.Delegate@Delegate)
{
return@delegate.Method.Name;
}
私有空间爆炸()
{
//做一些动作,比如。。。
}
私有无效HandleMyNumber(整数)
{
//做一些动作,比如。。。
}

正如其他人之前提到的,检索MethodInfo以获取方法名称的最简单方法是通过委托类型(如Action)。我不想为每个委托类型(如Action、Action、Action)指定重载,因为我不使用这些参数。相反,我可以将任何作为参数传递的方法强制转换为正确的类型。

我从未听说过这一点,但我建议您创建一个字符串变量,以便在调用中需要使用它时使用,并将此字符串保留在相应的方法旁边。您可能可以使用C#5.0引入的属性来实现这一点。它还简化了具有类似问题的INotifyPropertyChanged的实现。您可能需要将其封装在一个方法中,该方法将为您调用
invokereepeating
。您可以等待c#6和
nameof
操作符(请参见此),或者使用一些(不太正统的)解决方案,如expression。c#6.0应该有一个
nameof
操作符来执行此操作,但现在没有帮助。此问题的答案建议
新操作(FunctionName).Method.Name
。您必须指定
Action
Func
的适当通用版本。。。我认为它在重构和重载方面不会起到很好的作用。如果重命名多个重载中的一个,会更改哪个
nameof
用法?至少对于方法组,之后会立即投影一些类型信息,允许解决重载问题。这比需要的要复杂得多。@BenVoigt我不确定这是否比为其他地方维护的InvokereRepeating函数编写包装更复杂。这也正是一些注释()所建议的内容,而没有将其包装到实用程序类中。@BenVoigt您是对的,
public enum MyCoroutines
{ 
Coroutine1,
Coroutine2
}

InvokeRepeating(MyCoroutines.Coroutine1.ToString(), x, y);
public void Start()
{
    Invoke(
        methodName : GetMethodName((System.Action)Explode), 
        time: 1f);

    Invoke(
        methodName : GetMethodName((System.Action<int>)HandleMyNumber), 
        time: 2f);
}

public static string GetMethodName(System.Delegate @delegate)
{
    return @delegate.Method.Name;
}

private void Explode()
{
    // Do something Action like...   
}

private void HandleMyNumber(int number)
{
    // Do something Action<int> like...
}