4

我可以使用out带有递归方法的参数吗?如果可能的话,我该如何使用以下代码来做到这一点?

private void PrepareDir(out List<_File> listFiles,string root,string dirPath) {
    DirectoryInfo dirRoot = new DirectoryInfo(dirPath);
    FileInfo [] Files = dirRoot.GetFiles();
    dirPath = dirPath.Substring(root.Length);

    foreach (FileInfo file in Files) {
        _File _file = new _File();
        _file.Name = dirPath + "\\" + file.Name;
        _file.Path = file.FullName;
        _file.Size = file.Length;
        listFiles.Add(_file);
    }

    foreach (DirectoryInfo dir in dirRoot.GetDirectories()) {
        PrepareDir(out listFiles, root, dir.FullName);
    }
}

private void btnButton1_Click(object sender, EventArgs e) {
    List<_File> Files = new List<_File>();
    PrepareDir(out Files,currAddress, currAddress);
}
4

2 回答 2

5

我决定重写我的答案,以便更直接地说明为什么out在这里不需要使用。我写这篇文章很长,因为我认为您问题的根源更多在于不理解按值传递、按引用传递之间的区别,以及按引用传递的引用类型之间的常见混淆另请注意,这并不明确仅用于递归。

在 C# 中,引用类型默认按值传递。很多人可能会将引用类型与按引用传递混淆,但有一个重要的区别。为了让自己更清楚,我将按原样引用引用类型,并使用reforout关键字通过引用传递。

按值传递引用类型,因为它是对内存中某个存储位置的引用,因此您可以进行更改并保持更改。举这个例子。

public class MyRefType
{
    public int Value { get; set; }
}

public void Foo() {
    MyRefType type = new MyRefType();
    AddOne(type);
}

public void AddOne(MyRefType type) {
    type.Value++;
}

这里会发生的是,该类type现在的值为 1。这是引用类型的本质。如果type是 a struct,它在 Foo 方法中的值仍然为 0,因为创建了一个副本,而不是保存对该对象的引用。

现在我希望你理解了按值传递引用类型的语义,让我们真正谈谈按引用传递引用类型。这是使用outandref关键字完成的。请立即注意,在 CLR 中,out技术上不存在,只有ref存在。out实际上在元数据中表示为ref具有应用于它的特殊属性,并且它们应该被同等对待。

现在假设我们想在AddOne添加之前在方法中重新分配我们的引用类型。

public class MyRefType
{
    public int Value { get; set; }
}

public void Foo() {
    MyRefType type = new MyRefType();
    AddOne(type);
}

public void AddOne(MyRefType type) {
    type = new MyReferenceType();
    type.Value++;
}

因为我们仍然按值传递我们的引用类型,type所以方法中的值Foo仍然是 0。我们所做的只是初始化内存中的另一个存储位置,而不是重新分配原始存储位置)。但是我们想通过引用传递我们的引用类型所以我们真的应该这样做:

public class MyRefType
{
    public int Value { get; set; }
}

public void Foo() {
    MyRefType type = new MyRefType();
    AddOne(ref type);
}

public void AddOne(ref MyRefType type) {
    type = new MyReferenceType();
    type.Value++;
}

现在方法type中的值Foo将是 1。这是因为我们重用了引用指向的相同存储位置,而不是在内存中创建新位置。

那么这一切如何适用out呢?请记住,这与不同的使用语义out相同。ref不同之处在于,ref你可以在没有初始化引用的情况下离开方法,而使用out,你必须在方法返回之前显式地初始化它。

因此,在您在out这里使用的情况下,完全没有必要,因为您已经有现有的参考语义为您工作。我希望这能澄清一点。

于 2012-04-25T03:23:49.367 回答
2

您在代码示例中滥用了关键字out。您List<_File>作为引用类型传递,对该列表所做的任何更改都会影响调用者的列表。out当你想重新分配调用者的标识符时,你只需要传递一个参数。

考虑:

public bool Foo()
{
  List<int> list = new List<int>();
  list.Add(1);
  Bar(out list);
  return list.Contains(1);
}

public void Bar(out List<int> list)
{
  list = new List<int>();
  list.Add(2);
}

Foo将返回错误。

另一方面,如果Bar是这样的:

public void Bar(List<int> list)
{
  list = new List<int>();
  list.Add(2);
}

然后Foo将返回true。有关out更多详细信息,请参阅。

您的代码可以在不使用out. 而且,实际上,不会编译 - 并且使其编译会增加您尝试做的事情的不必要的复杂性。不要out在你的情况下使用。

于 2012-04-25T03:13:04.080 回答