将引用(和 Unity 的 WWW.progress)传递给 Coroutines/IEnumerators
Passing references (And Unity's WWW.progress) to Coroutines/IEnumerators
我使用 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 class下载东西,我在传递www.progress作为参考时也出现此错误:
A property or indexer 'UnityEngine.WWW.progress' may not be passed as 'ref' or 'out' parameter
从函数参数中删除 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 参数传递给交互器。
考虑一下
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
参数的语法糖。
因此,您的方法不仅行不通(C# 不会为您做,yield
带走了很多编码)而且行不通。
您需要以某种方式将浮点数装箱,无论您是持有对同一个浮点数的 object
引用,作为引用类型可以由迭代器更新,还是类型化盒子像:
private class TypedBox<T> where T : struct
{
public T Value { get; set; }
public TypedBox(T value)
{
Value = value;
}
}
这再次允许您通过引用类型访问值,但没有转换成本。
更多时候,根据传入的任何值迭代值更有用。
我使用 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 class下载东西,我在传递www.progress作为参考时也出现此错误:
A property or indexer 'UnityEngine.WWW.progress' may not be passed as 'ref' or 'out' parameter
从函数参数中删除 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 参数传递给交互器。
考虑一下
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
参数的语法糖。
因此,您的方法不仅行不通(C# 不会为您做,yield
带走了很多编码)而且行不通。
您需要以某种方式将浮点数装箱,无论您是持有对同一个浮点数的 object
引用,作为引用类型可以由迭代器更新,还是类型化盒子像:
private class TypedBox<T> where T : struct
{
public T Value { get; set; }
public TypedBox(T value)
{
Value = value;
}
}
这再次允许您通过引用类型访问值,但没有转换成本。
更多时候,根据传入的任何值迭代值更有用。