在Unity中使用coroutines或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:我能想到的最干净的事情是使用函数的名称创建一个const字符串,并将它放在函数本身之前。所以忘记更改字符串会更难,因为它就在它上面,而且我也只需要更改一个const字符串来改变所有的协程。
谢谢!
答案 0 :(得分:9)
啊......如果它是下一个C#版本,你可以使用 nameof 运算符。
目前,这对您的事业有帮助吗?
private static string GetFunctionName(Action method)
{
return method.Method.Name;
}
使用:
调用string methodName = GetFunctionName(SendChangedValues);
您可能想要探索不同的委托类型.. Action,Func等。
上面唯一的问题是,对于每个方法签名,您可能需要定义正确的签名/重载来获取名称。
答案 1 :(得分:4)
我在我的代码库中使用以下内容,为invokerepeating推断。
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);
}
}
像这样使用
public class MyBehaviour : MonoBehaviour {
void Start(){
this.InvokeLater(1f, DoSomething1SecondLater);
}
public void DoSomething1SecondLater(){
Debug.Log("Welcome to the future");
}
}
答案 2 :(得分:3)
协同程序确实允许 IF 你没有传递额外的参数。第一个示例in the documentation显示签名为Coroutine StartCoroutine(IEnumerator routine);
的重载:
using UnityEngine;
using System.Collections;
public class Example : MonoBehaviour {
void Start() {
print("Starting " + Time.time);
StartCoroutine(WaitAndPrint(2.0F));
print("Before WaitAndPrint Finishes " + Time.time);
}
IEnumerator WaitAndPrint(float waitTime) {
yield return new WaitForSeconds(waitTime);
print("WaitAndPrint " + Time.time);
}
}
不幸的是, InvokeRepeating
没有同样的重载。你应该能够使用反射在那里完成它,尽管如其他一些答案所述。
答案 3 :(得分:2)
我理解你的问题而且我没有为此提供一个解决方案。
使用lambda表达式作为一种解决方法可能会有所帮助,就像在blog post中一样。
它描述了一种通过传递将被评估为Expression
的{{1}}来确定方法名称的方法。从那里,您可以提取相关信息。
答案 4 :(得分:2)
我记得在另一个背景下做了类似的事情。它是这样的:
您声明了一个使用原始方法的自己的方法:
public static void MyInvokeRepeating<T>(Func<T> method)
{
InvokeRepeating(method.Method.Name, SEND_RATE, SEND_RATE);
}
然后像这样调用你的方法
MyInvokeRepeating(someObject.SomeFunction);
更好的是,制作一个扩展方法。
答案 5 :(得分:2)
您可以通过静态反射(至少在.NET 4中,可能是3.5及以下)
来完成此操作// This
InvokeRepeating(((MethodCallExpression)((Expression<Action<string>>)(x => x.ToString())).Body).Method.Name, SEND_RATE, SEND_RATE);
// Is the same as
InvokeRepeating("ToString", SEND_RATE, SEND_RATE);
您只需要知道您正在调用的功能的签名,并相应地替换上面示例中的操作。
答案 6 :(得分:2)
从您拥有的协同程序中创建enum
:
public enum MyCoroutines
{
Coroutine1,
Coroutine2
}
InvokeRepeating(MyCoroutines.Coroutine1.ToString(), x, y);
这样您就没有拼写错误功能名称的危险,而且您可以轻松找到并替换它们。它也非常适合播放声音和动画。
答案 7 :(得分:1)
当您处理方法(不是属性或字段)时,不需要lambda表达式。
您可以编写一个带有委托的InvokeRepeating
包装器。致电代理人GetInvocationList
,获取MethodInfo
,其名称为。{/ p>
答案 8 :(得分:0)
这是我对此事的看法,因为我最近在 UnityEvent 监听器的上下文中偶然发现了这个问题,这些监听器也存储并且只能通过方法的名称检索。在处理具有不同签名的事件处理程序时,我的方法更有意义,但它也适用于任何 Action 和 Invoke 。
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...
}
正如其他人之前提到的,检索 MethodInfo 以获取方法名称的最简单方法是通过委托类型,例如 Action 。我不想为每个委托类型指定重载,例如Action,Action,Action,因为我不使用这些参数。相反,我可以将我作为参数传递的任何方法转换为正确的类型。