0

Unity3Dでこれを行っていることを明確にするために、これは重要な場合と重要でない場合がありますか?

生成されないIEnumerator関数にrefによって値を渡すことができるかどうかを調べようとしています。降伏するものでそれを行おうとすると、VS2010は文句を言います(「イテレータはrefまたはoutパラメータを持つことができません」)が、降伏関数を呼び出すがそれ自体を降伏しない同様のIEnumerator関数で呼び出しをラップすると、エラーはなくなり、動作しているように見えます。私は私が予期しない行動の土地にいるのか、それともこれが正常な行動であるのかを調べようとしています。

これが私がしていることの例です:

IEnumerator Wrapper(ref int value)
{
    int tmp = ++value;    // This is the ONLY place I want the value
    return Foo(tmp);      // of the ref parameter to change!  
}                         // I do _NOT_ want the value of the ref
                          // parameter to change in Foo()!
IENumerator Foo(int value)
{
    // blah blah
    someFunc(value);
    someSlowFunc();
    yield return null;
    yield return null;
}
4

1 に答える 1

1

いいね。最上位の関数はIEnumeratorを返すだけですが、それ以外は通常の関数です。一番下の関数IEnumerator[コンパイラーによってファンキーなクラスに変換される]であるため、ref値を持つことはできません。

最上位の関数は次のように記述できます。

 void Wrapper(ref int value, out IEnumerator coroutine)
 {
     int tmp = ++value;
     coroutine = Foo(tmp);
 }

これはもう少し厄介ですが、これが2つのデータを処理する通常の関数であることがわかります。参照によって渡されるintと、[この例ではoutを使用して]返すIEnumerator[クラスのみ]。


補足:これは、舞台裏での仕組みです。

    static void Main(string[] args)
    {
        //Lets get the 'IEnumerable Class' that RandomNum gets compiled down into.
        var IEnumeratorClass = RandomNum(10, 10);

        //All an IEnumerable is is a class with 'GetEnumerator'... so lets get it!
        var IEnumerableClass = IEnumeratorClass.GetEnumerator();

        //It can be used like so:
        while (IEnumerableClass.MoveNext())
        {
            Console.WriteLine(IEnumerableClass.Current);
        }

        Console.WriteLine(new String('-', 10));

        //Of course, that's a lot of code for a simple job.
        //Luckily - there's some nice built in functionality to make use of this.
        //This is the same as above, but much shorter
        foreach (var random in RandomNum(10, 10)) Console.WriteLine(random);

        Console.WriteLine(new String('-', 10));

        //These simple concepts are behind Unity3D coroutines, and Linq [which uses chaining extensively]
        Enumerable.Range(0, 100).Where(x => x % 2 == 0).Take(5).ToList().ForEach(Console.WriteLine);

        Console.ReadLine();
    }

    static Random rnd = new Random();
    static IEnumerable<int> RandomNum(int max, int count)
    {
        for (int i = 0; i < count; i++) yield return rnd.Next(i);
    }

    //This is an example of what the compiler generates for RandomNum, see how boring it is?
    public class RandomNumIEnumerableCompiled : IEnumerable<int>
    {
        int max, count;
        Random _rnd;
        public RandomNumIEnumerableCompiled(int max, int count)
        {
            this.max = max;
            this.count = count;
            _rnd = rnd;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new RandomNumIEnumeratorCompiled(max, count, rnd);
        }

        IEnumerator<int> IEnumerable<int>.GetEnumerator()
        {
            return new RandomNumIEnumeratorCompiled(max, count, rnd);
        }

    }
    public class RandomNumIEnumeratorCompiled : IEnumerator<int>
    {
        int max, count;
        Random _rnd;
        int current;
        int currentCount = 0;
        public RandomNumIEnumeratorCompiled(int max, int count, Random rnd)
        {
            this.max = max;
            this.count = count;
            _rnd = rnd;
        }

        int IEnumerator<int>.Current { get { return current; } }

        object IEnumerator.Current { get { return current; } }

        public bool MoveNext()
        {
            if (currentCount < count)
            {
                currentCount++;
                current = rnd.Next(max);
                return true;
            }
            return false;
        }

        public void Reset() { currentCount = 0; }
        public void Dispose() { }
    }
于 2012-08-01T04:52:07.590 に答える