c# - 没有 GC 的无限方法参数

标签 c# unity3d memory-management variadic-functions

我正在尝试制作一个可以接收无限量参数而无需装箱 GC 的函数。

我知道这可以通过 params 关键字来完成,但它会创建 GC。还要了解您可以将数组传递给函数,但我想知道是否可以传递无限的方法参数而不创建 GC 并且不创建数组或列表并将其传递给列表。。 p>

这是带有 param 代码的示例:

void Update()
{
    GameObject player1 = GameObject.Find("Player1");
    GameObject player2 = GameObject.Find("Player2");

    GameObject enemy1 = GameObject.Find("Enemy1");
    GameObject enemy2 = GameObject.Find("Enemy2");
    GameObject enemy3 = GameObject.Find("Enemy3");

    Vector3 newPos = new Vector3(0, 0, 0);
    moveObjects(newPos, 3f, player1, player2, enemy1, enemy2, enemy3);
}

void moveObjects(Vector3 newPos, float duration, params GameObject[] objs)
{
    for (int i = 0; i < objs.Length; i++)
    {
        //StartCoroutine(moveToNewPos(objs[i].transform, newPos, duration));
    }
}

即使在 StartCoroutine 函数被注释掉的情况下执行时,它也会分配 80 字节。起初,我认为这是因为我使用了 foreach 循环然后我将其更改为 for 循环但它仍然创建 GC 然后我意识到 params GameObject [] 导致了它。有关这方面的更多视觉信息,请参见下面的分析器:

enter image description here

那么,我怎样才能创建一个接受无限参数而不生成 GC 的方法?

请忽略 Update 函数中使用的 GameObject.Find 函数。这只是一个例子,用于在运行时获取我想要的对象的引用。我实现了一个脚本来处理这个问题,但与这个问题中的内容无关。

最佳答案

是的,可以在不引起内存分配的情况下创建具有无限参数的函数。

您可以使用未记录的 __arglist 关键字并将我们无限的 params 包装在其中。

将你的 moveObjects(newPos, 3f, player1, player2, enemy1, enemy2, enemy3) 更改为 moveObjects(newPos, 3f, __arglist(player1, player2, enemy1, enemy2, enemy3) )

moveObjects函数中,将params GameObject[] objs替换为__arglist。将 __arglist 放入 ArgIterator,然后对其进行循环,直到 ArgIterator.GetRemainingCount 不再超过 0。 p>

要从循环中的参数中获取每个值,请使用 ArgIterator.GetNextArg 获取 TypedReference,然后使用 TypedReference.ToObject 进行转换object 到参数中传递的 Object 类型,在您的示例中为 GameObject

整体一起变化:

void Update()
{
    GameObject player1 = GameObject.Find("Player1");
    GameObject player2 = GameObject.Find("Player2");

    GameObject enemy1 = GameObject.Find("Enemy1");
    GameObject enemy2 = GameObject.Find("Enemy2");
    GameObject enemy3 = GameObject.Find("Enemy3");

    Vector3 newPos = new Vector3(0, 0, 0);
    moveObjects(newPos, 3f, __arglist(player1, player2, enemy1, enemy2, enemy3));
}

void moveObjects(Vector3 newPos, float duration, __arglist)
{
    //Put the arguments in ArgIterator
    ArgIterator argIte = new ArgIterator(__arglist);

    //Iterate through the arguments in ArgIterator
    while (argIte.GetRemainingCount() > 0)
    {
        TypedReference typedReference = argIte.GetNextArg();
        object tempObj = TypedReference.ToObject(typedReference);

        GameObject obj = (GameObject)tempObj;
        //StartCoroutine(moveToNewPos(obj.transform, newPos, duration));
    }
}

虽然这应该可以解决您的问题,但值得注意的是它是一个未记录的功能,这意味着它可能有一天会停止工作。如果您关心这一点,那么应该使用数组。

编辑:

John Skeet 提到了在某些平台上可能存在的不兼容性。我再次进行了测试,它适用于我测试过的所有设备。我在 Windows 和 Android 上都做了测试,它在 Windows 和 Android 上都有效。我也希望它也能在 iOS 上运行。懒得切换到 Mac,然后摆弄 Xcode 进行测试,但应该没有问题。

请注意,您必须使用 .NET>=4.6 才能正常工作

这样做:

1。转到播放器设置,将脚本运行时版本更改为“实验版(.Net 4.6 等效版本)”

2。将 API 兼容性级别更改为 .NET 4.6

3。将脚本后端更改为 Mono 而不是 IL2CPP。不支持 IL2CPP,因为 Unity 没有在其上实现它。

关于c# - 没有 GC 的无限方法参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49953350/

相关文章:

c# - wpf 应用程序中的自定义组合框选定文本

c# - 在 C# 中实例化实现 .NET 接口(interface)的 IronPython 类型

c# - 让 C# 和 Python 为这个机器学习任务进行通信的最佳方法是什么?

C++ 在具有 float 组的结构的二维 vector 上使用删除

ios - 在 UIWebView 中加载 NSURLRequest - 堆不断增长

objective-c - 了解已修复的错误 : Sending NSError *const __strong* to parameter

c# - 将数据集传递给 SQL Server 存储过程

c# - 如何在Linq中通过属性获取元素的值

c# - 如何使用曲线平滑地制作跳跃动画?

c# - 从谷歌翻译方括号中拆分字符串