【问题标题】:Alternative to using ref in foreach?在 foreach 中使用 ref 的替代方法?
【发布时间】:2018-01-04 22:32:37
【问题描述】:

我有一个带有类似签名的修改方法

private bool Modify(ref MyClass obj);

这将对obj 进行修改并用它的返回值指示成功。 Modify 没有重新分配引用(我知道这行不通),只是修改实例字段,所以我想用它来执行以下操作:

foreach(MyClass obj in myList)
{
    bool success = Modify(obj);
    // do things depending on success
}

我在编译时遇到了问题,因为obj 是“没有通过ref 关键字传递”。但是,如果我这样输入 ref 关键字:

bool success = Modify(ref obj);

我得到“不能使用obj 作为ref/out,因为它是一个'foreach 迭代变量”。我知道 foreach 使用不可变的迭代器,这就是它不起作用的原因。

我的问题是最简单的替代方法是什么?

我尝试过使用

foreach(int i = 0; i < myList.Count; i++)
{
    bool success = Modify(ref myList[i]);
    // do things depending on success
}

但我得到“属性或索引器可能不会作为超出 ref 参数传递”。

感谢您的帮助。

【问题讨论】:

  • 也许使用 simplefor 循环而不是 foreach
  • 为什么需要通过 ref 传递对象给这个 Modify 函数?
  • 可以不使用ref修改obj的属性。使用ref 允许您修改引用本身。这几乎肯定不是您想要的。
  • 定义如何修改它。如果要更新属性或字段,则不需要 ref 参数。如果您完全重新分配参考,那是一个单独的问题。
  • 请更新您的问题以包括您如何在Modify 中使用obj

标签: c# foreach ref


【解决方案1】:

C# 中的任何类型实际上都是按值传递。当你将一个类的实例传递给一个方法时,实际上传递的不是实例本身,而是一个对它的引用,它本身按值传递时间>。所以实际上你将一个类的实例作为引用传递——这就是你称它们为引用类型的原因。

在您的情况下,您只需修改方法中该引用值引用的现有实例,无需使用ref-关键字。

foreach(var m in myList)
{
    MyMethod(m);
}

MyMethod(MyClass instance)
{
    instance.MyProperty = ...
}

如果您真的通过引用传递引用,您将在循环内的每次迭代中重新分配obj,这在foreach 块中是不允许的。这将类似于以下内容:

foreach(var m in myList)
{
    m = new MyClass();
}

另一方面,您也可以使用经典的 for 循环。但是,您需要一个临时变量来存储方法的结果:

for(int i = 0; i < myList.Length; i++)
{
    var tmp = myList[i];
    MyMethod(ref tmp);
    myList[i] = tmp;
}

【讨论】:

  • 这真正回答了所提出的概念性问题,无论它是否是 OP 的正确解决方案
【解决方案2】:

你说

修改不是重新分配引用

因此,Modify(ref MyClass) 函数没有理由需要通过ref 传递参数。

您应该能够通过按值传递对象引用来执行相同的“修改”,无论是什么(请澄清),即删除 ref 关键字。

因此,这里的修复应该是将修改函数签名从 Modify(ref MyClass) 更改为 Modify(MyClass)

【讨论】:

  • 修改很复杂,我认为与示例无关。
【解决方案3】:

使用LINQ解决。

我的代码:

    private static List<string> _test = new List<string>();

    public List<string> Test { get => _test; set => _test = value; }


    static void Main(string[] args)
    {
        string numString = "abcd";

        _test.Add("ABcd");
        _test.Add("bsgd");

        string result = _test.Where(a => a.ToUpper().Equals(numString.ToUpper()) == true).FirstOrDefault();

        Console.WriteLine(result + " linq");
    }

【讨论】:

  • 这如何回答关于在循环中修改列表的问题?
  • 我提出了一种无需使用 for 或 foreach 语句即可解决的方法。
  • 发问者似乎在寻找比 for ref in for 或 foreach 更简单的方法。
【解决方案4】:

使用临时变量绕过消息

foreach(MyClass obj in myList)
{
    MyClass objTemp = obj;
    bool success = Modify(ref objTemp);
    // do things depending on success
}

private MyMethod(ref MyClass instance)
{
    instance.MyProperty = ...
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-02
    • 2018-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-17
    相关资源
    最近更新 更多