Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# CS8176:迭代器不能具有按引用局部变量_C#_Ref_Enumerator - Fatal编程技术网

C# CS8176:迭代器不能具有按引用局部变量

C# CS8176:迭代器不能具有按引用局部变量,c#,ref,enumerator,C#,Ref,Enumerator,在给定的代码中是否存在此错误的真正原因,或者只是在需要跨interator步骤引用的一般用法中可能会出错(在本例中不是这样) 编译器想用局部变量作为字段重写迭代器块,以保留状态,不能将ref类型作为字段。是的,你是对的,它不会跨越产生,因此从技术上讲,它可能会被重写以根据需要重新声明,但这使得人类需要记住非常复杂的规则,简单的更改会破坏代码。一条毛毯说“不”要容易得多 此场景中的解决方法(或类似地使用async方法)通常是辅助方法;例如: IEnumerable枚举静态() { (字符串值,in

在给定的代码中是否存在此错误的真正原因,或者只是在需要跨interator步骤引用的一般用法中可能会出错(在本例中不是这样)


编译器想用局部变量作为字段重写迭代器块,以保留状态,不能将ref类型作为字段。是的,你是对的,它不会跨越
产生
,因此从技术上讲,它可能会被重写以根据需要重新声明,但这使得人类需要记住非常复杂的规则,简单的更改会破坏代码。一条毛毯说“不”要容易得多

此场景中的解决方法(或类似地使用
async
方法)通常是辅助方法;例如:

IEnumerable枚举静态()
{
(字符串值,int-next)GetNext(int-index)
{
参考变量p=参考道具[指数];
返回(p.name,p.next);
}
foreach(int i在dict.Values中)
{
(var名称,var next)=GetNext(i);
产生返回名称;
while(下一步>=0)
{
(名称,下一个)=获取下一个(下一个);
产生返回名称;
}
}
}

IEnumerable枚举静态()
{
字符串GetNext(ref int next)
{
参考变量p=参考道具[下一步];
next=p.next;
返回p.name;
}
foreach(int i在dict.Values中)
{
var-next=i;
收益返回GetNext(参考next);
while(下一步>=0)
{
收益返回GetNext(参考next);
}
}
}
局部函数不受迭代器块规则的约束,因此可以使用ref局部变量

无法将ref传递给下一个IEnumerator.MoveNext()。但事实并非如此

编译器创建一个状态机类来保存运行时继续下一次迭代所需的数据。就是那个类不能包含ref成员

编译器可以检测到变量只在有限的范围内需要,不需要添加到该状态类中,但正如Marc在回答中所说的,这是一个昂贵的特性,几乎没有额外的好处。记住。所以你可以要求它,但一定要解释它的用途

值得一提的是,Marc的版本比此设置快约4%(根据):

public class StructArrayAccessBenchmark
{
    struct Prop
    {
        public string name;
        public int next;
    }

    private readonly Prop[] _props = 
    {
        new Prop { name = "1-1", next = 1 }, // 0
        new Prop { name = "1-2", next = -1 }, // 1

        new Prop { name = "2-1", next = 3 }, // 2
        new Prop { name = "2-2", next = 4 }, // 3
        new Prop { name = "2-2", next = -1 }, // 4
    };

    readonly Dictionary<string, int> _dict = new Dictionary<string, int>
    {
        { "1", 0 },
        { "2", 2 },
    };

    private readonly Consumer _consumer = new Consumer();

    // 95ns
    [Benchmark]
    public void EnumerateRefLocalFunction() => enumerateRefLocalFunction().Consume(_consumer);

    // 98ns
    [Benchmark]
    public void Enumerate() => enumerate().Consume(_consumer);

    public IEnumerable<string> enumerateRefLocalFunction()
    {
        (string value, int next) GetNext(int index)
        {
            ref var p = ref _props[index];
            return (p.name, p.next);
        }

        foreach (int i in _dict.Values)
        {
            var (name, next) = GetNext(i);
            yield return name;

            while (next >= 0)
            {
                (name, next) = GetNext(next);
                yield return name;
            }
        }
    }

    public IEnumerable<string> enumerate()
    {
        foreach (int i in _dict.Values)
        {
            var p = _props[i];
            int next = p.next;
            yield return p.name;
            while (next >= 0)
            {
                p = _props[next];
                next = p.next; 
                yield return p.name;
            }
        }
    }

@菲达,这取决于你;我希望它会“按设计”关闭,而且:我支持closure我希望这是一个现在不值得追求的角落案例,但支持关闭吗?好的,我期待积压工作。(附言:我接受,甚至不会尝试)@firda,因为编译器能够证明它的案例数量有限,而且对人类来说很复杂
using System.Collections.Generic;

namespace ConsoleApp1
{
    class Program
    {
        class Test
        {
            struct Prop
            {
                public string name;
                public int next;
            }
            Prop[] props;
            Dictionary<string, int> dict;
            public IEnumerable<string> Enumerate()
            {
                foreach (int i in dict.Values)
                {
                    ref var p = ref props[i]; //< CS8176: Iterators cannot have by-reference locals
                    int next = p.next;
                    yield return p.name;
                    while (next >= 0)
                    {
                        p = ref props[next];
                        next = p.next;
                        yield return p.name;
                    }
                }
            }
        }
        static void Main(string[] args)
        {
        }
    }
}
public class StructArrayAccessBenchmark
{
    struct Prop
    {
        public string name;
        public int next;
    }

    private readonly Prop[] _props = 
    {
        new Prop { name = "1-1", next = 1 }, // 0
        new Prop { name = "1-2", next = -1 }, // 1

        new Prop { name = "2-1", next = 3 }, // 2
        new Prop { name = "2-2", next = 4 }, // 3
        new Prop { name = "2-2", next = -1 }, // 4
    };

    readonly Dictionary<string, int> _dict = new Dictionary<string, int>
    {
        { "1", 0 },
        { "2", 2 },
    };

    private readonly Consumer _consumer = new Consumer();

    // 95ns
    [Benchmark]
    public void EnumerateRefLocalFunction() => enumerateRefLocalFunction().Consume(_consumer);

    // 98ns
    [Benchmark]
    public void Enumerate() => enumerate().Consume(_consumer);

    public IEnumerable<string> enumerateRefLocalFunction()
    {
        (string value, int next) GetNext(int index)
        {
            ref var p = ref _props[index];
            return (p.name, p.next);
        }

        foreach (int i in _dict.Values)
        {
            var (name, next) = GetNext(i);
            yield return name;

            while (next >= 0)
            {
                (name, next) = GetNext(next);
                yield return name;
            }
        }
    }

    public IEnumerable<string> enumerate()
    {
        foreach (int i in _dict.Values)
        {
            var p = _props[i];
            int next = p.next;
            yield return p.name;
            while (next >= 0)
            {
                p = _props[next];
                next = p.next; 
                yield return p.name;
            }
        }
    }
|                    Method |      Mean |    Error |   StdDev |
|-------------------------- |----------:|---------:|---------:|
| EnumerateRefLocalFunction |  94.83 ns | 0.138 ns | 0.122 ns |
|                 Enumerate |  98.00 ns | 0.285 ns | 0.238 ns |