从函数返回内存流

时间:2009-02-02 16:22:49

标签: c#

在您看来,最好从函数返回一个新分配的内存流,还是将其传递给函数?例如,

void Foo(MemoryStream m) 
{ 
   m.Write(somebuffer, 0, somebuffer.Length); 
}

void MemoryStream Foo()
{
    MemoryStream retval = new MemoryStream();
    retval.Write(somebuffer, 0, somebuffer.Length);
    return retval;
}

10 个答案:

答案 0 :(得分:17)

这有点像询问是否应该从方法返回一个字符串或者接受一个StringBuilder并附加到它。答案取决于用例是什么。

调用者是否可能希望使用包含某些数据的现有流来调用您的方法?他们可能想使用相同的流多次调用它?如果是这样,采用MemoryStream的版本将更有效。另一方面,如果他们只想要一次数据,那么将它作为MemoryStream(或者更简单地,作为字节数组)返回可能更合适。

不幸的是,从描述中我们无法确切地知道发生了什么。当然,你可以将它们实现为重载并从另一个中调用一个。

答案 1 :(得分:7)

内存流传递给函数,返回函数的内存流不应互换使用。您描述的方法有两个不同的用途。

  • 将函数传递给函数是为了让函数对函数执行某些操作。

  • 从函数中返回一些内容是调用者应该对结果做某事。

你说的是两个不同的东西,苹果和橘子。

答案 2 :(得分:4)

我总是将流传递给函数。这允许它与调用者选择的任何流一起工作,例如直接进入文件而不进行任何缓冲。

答案 3 :(得分:2)

您可以安全地从功能中返回它。您必须调用Dispose()或将其放在using子句中,因为它实现了IDisposable。

答案 4 :(得分:1)

你的第二个更好。如果可能的话,我总是尽量避免在函数内部变异。

答案 5 :(得分:1)

经过一番思考之后,我认为它归结为Foo方法的预期语义。是吗:

  • 创建流的操作(例如File.Open()
  • 修改流的操作(例如something.WriteXml()

如果答案是“创建流”,请让它返回一个流。如果它修改了一个流,则将该流传递给。

如果答案是“两者中的某些”,那么拆分方法以使其只有一个责任可能是有意义的。

答案 6 :(得分:0)

没有两个差异。在第一个实例中,调用者将控制内存流,在第二个实例中,您可以执行以下操作:

using (MemoryStream ms = Foo())
{
  //Do Stuff here.
}

最重要的是要记住正确处理它。

答案 7 :(得分:0)

我更喜欢注射形式。它消除了代码与MemoryStream之间的直接耦合,使其更易于测试。

public void Foo(Stream stream)
{
    stream.Write(somebuffer, 0, somebuffer.Length);
}

现在,我可以使用任何实现Stream的类来测试Foo,包括模拟类。

通常情况下,我会在类的构造函数中进行注入而不是单独的方法,但这个想法基本相同。

public class FooClass
{
   public Stream FooStream { get; private set; }

   public FooClass() : this(null) { }

   public FooClass( Stream stream )
   {
       // provide a default if not specified
       this.FooStream = stream ?? new MemoryStream();
   }

   public void Foo()
   {
       this.FooStream.Write( somebuffer, 0, somebuffer.Length );
   }
}

答案 8 :(得分:0)

我倾向于第一个,原因有两个:

  1. 谁“拥有”内存流的语义是清楚的。调用者创建了它,所以由调用者来解决它(对于非托管资源的其他类型的流更是一个问题)
  2. Foo可以与您在流上运行的其他方法结合使用
  3. 也就是说,如果Foo的主要目的是作为MemoryStreams的工厂方法(类似于File.Open等),第二种方法更有意义。

答案 9 :(得分:0)

因为流是需要显式处理的资源(内存,文件,网络),所以最好应用RAII方法来处理它们。这意味着初始化它们的函数必须对发布负责(我们在C#中使用“使用”keyord)。为了启用这种模式,我说接受流作为参数。这样,调用者可以决定何时创建和处理流。当你在它时,你的方法接受任何流实现;它似乎不仅仅适用于MemoryStream。