将引用(以及Unity';s WWW.progress)传递给Coroutines/IE分子

本文关键字:Coroutines 分子 IE progress WWW 以及 引用 Unity | 更新日期: 2023-09-27 18:19:57

我已经使用Unity 5在C#中创建了一个协程,我想传递一个对它的引用。它似乎不起作用,所以我制作了一个测试脚本来隔离以下错误
error CS1623: Iterators cannot have ref or out parameters

这是测试脚本:

using UnityEngine;
using System.Collections;
public class TEMP : MonoBehaviour {
    // Use this for initialization
    void Start () {
        float var = 3.141f;
        StartCoroutine ( test (ref var) );
    }
    IEnumerator test (ref float value) {
        for (int i = 1; i <= 10; i++) {
            Debug.Log (value);
            yield return null;
        }
    }
}

此外,在我的实际脚本上,我正在使用Unity的WWW类下载一些东西,当我传递WWW.progress作为参考时,我也会收到这个错误:
A property or indexer 'UnityEngine.WWW.progress' may not be passed as 'ref' or 'out' parameter

将引用(以及Unity';s WWW.progress)传递给Coroutines/IE分子

从函数参数中删除ref。

// Use this for initialization
void Start () {
    float var = 3.141f;
    StartCoroutine ( test (var) );
}
IEnumerator test (float value) {
    for (int i = 1; i <= 10; i++) {
        Debug.Log (value);
        yield return null;
    }
}

根据您的要求,您可以使用out参数执行以下操作。我不确定你打算如何使用这些方法,但我认为你对ref参数及其工作方式的想法是错误的。

class Program
{
    static void Main(string[] args)
    {
        float var = 3.14f;
        StartCoroutine(test(var), out var);
    }
    static IEnumerator test(float value)
    {
        for (int i = 1; i <= 10; i++)
        {
            Console.WriteLine(value);
            yield return value + 1;
        }
    }
    static void StartCoroutine(IEnumerator test, out float update)
    {
        update = 0;
        while (test.MoveNext())
        {
            update++;
            Console.WriteLine("Executing..." + update);
        }
    }
}

然而,您永远无法将ref或out参数传递给interator。

考虑

IEnumerator test (float value)
{
  for (int i = 1; i <= 10; i++)
  {
    Debug.Log(value);
    yield return null;
  }
}

像这样的东西的句法糖吗

private class Iterator : IEnumerable<object>, IEnumerator<object>
{
  private int _state;
  private int _threadId = Environment.CurrentManagedThreadId;
  private object _current;
  private float _value;
  int i;
  public Iterator(float value)
  {
    _value = value;
  }
  public object Current‎
  {
    get { return _current; }
  }
  object IEnumerator.Current
  {
    get { return _current; }
  }
  public IEnumerator<object> GetEnumerator()
  {
    // If we're on the same thread and its the first call, reuse this object as the enumerator
    // otherwise create a fresh one for new call (so we don't have buggy overlaps) or a different
    // thread (to avoid a race on that first call).
    Iterator iter = _state == 0 && _threadId == Environment.CurrentManagedThreadId ? this : new Iterator(_value);
    iter._state = 1;
    return iter;
  }
  IEnumerator IEnumerable.GetEnumerator()
  {
    return GetEnumerator();
  }
  public bool MoveNext()
  {
    switch(_state)
    {
      case 1:
        i = 1;
        _state = 2;
        goto case 2;
      case 2:
        if (i <= 10)
        {
          Debug.Log(_value);
          _current = null;
          ++i;
          return true;
        }
        _state = -1;
        break;
    }
    return false;
  }
  public void Dispose()
  {
  }
  public void Reset()
  {
    throw new NotSupportedException();
  }
}
private IEnumerator test(float value)
{
  return new Iterator(value);
}

现在,考虑一下您的float参数已经成为实现中的float字段。由于不能有ref字段,因此不能将其作为ref参数的语法糖。

因此,您的方法不仅不起作用(由于yield占用了大量编码,C#不会为您做这件事),而且也不起作用。

您需要以某种方式框住float,无论您持有对同一float的object引用,该引用类型可以由迭代器更新,还是像这样的类型框

private class TypedBox<T> where T : struct
{
  public T Value { get; set; }
  public TypedBox(T value)
  {
    Value = value;
  }
}

这再次允许您通过引用类型访问值,但不需要铸造成本。

通常情况下,根据传入的任何值迭代值更有用。