c# - what - Devolución de la secuencia de memoria de la función
what is memory stream c# (10)
En sus opiniones, ¿es mejor devolver una secuencia de memoria recién asignada desde una función o pasarla a la función? Por ejemplo,
void Foo(MemoryStream m)
{
m.Write(somebuffer, 0, somebuffer.Length);
}
o
void MemoryStream Foo()
{
MemoryStream retval = new MemoryStream();
retval.Write(somebuffer, 0, somebuffer.Length);
return retval;
}
Después de pensar un poco más, creo que se trata de la semántica prevista del método Foo
. Lo es:
- Una operación que crea una secuencia (por ejemplo,
File.Open()
) - Una operación que modifica una secuencia (por ejemplo,
something.WriteXml()
)
Si la respuesta es "crea una secuencia", haga que devuelva una secuencia. Si modifica una secuencia, pase la secuencia en.
Si la respuesta es "algo de ambos", puede tener sentido dividir el método para que tenga una sola responsabilidad.
Debido a que los flujos son recursos que necesitan eliminación explícita (memoria, archivo, red), es mejor aplicar un enfoque RAII para manejarlos. Eso significa que la función que los inicializa debe ser responsable con el lanzamiento (tenemos "usar" keyord en C # solo para eso). Para habilitar este patrón, digo aceptar la transmisión como un parámetro. De esta forma, la persona que llama puede decidir cuándo crear y eliminar la transmisión. Mientras lo haces, haz que tu método acepte cualquier implementación de flujo; no parece que necesite funcionar solo para MemoryStream.
Esto es un poco como preguntar si debe devolver una cadena de un método o tomar un StringBuilder y anexarlo. La respuesta depende de cuál sea el caso de uso.
¿Es probable que la persona que llama querrá llamar a su método con una transmisión existente que contenga algunos datos? ¿Podrían querer llamarlo varias veces con la misma transmisión? Si es así, la versión que toma el MemoryStream sería más eficiente. Por otro lado, si solo quieren los datos una vez, devolverlos como un MemoryStream (o, más simplemente, como una matriz de bytes) puede ser más apropiado.
Desafortunadamente de la descripción no podemos decir realmente qué está pasando. Por supuesto, puede implementar ambas como sobrecargas y llamar a una de la otra.
Me inclinaría hacia el primero por dos razones:
- La semántica de quién "posee" el flujo de memoria es clara. La persona que llamó lo creó, por lo que le corresponde a la persona que llama deshacerse de él (esto es más un problema con otros tipos de transmisión que se aferran a recursos no administrados).
-
Foo
se puede usar junto con otros métodos que operan en tu transmisión
Dicho esto, si el propósito principal de Foo
es como un método de fábrica para MemoryStreams (similar a algo como File.Open, etc.), el segundo enfoque tiene más sentido.
No hay dos muchas diferencias. En la primera instancia, la persona que llama tendrá control sobre la secuencia de la memoria y, en la segunda instancia, puede hacer algo como esto:
using (MemoryStream ms = Foo())
{
//Do Stuff here.
}
Lo más importante es recordar deshacerse de él correctamente.
Puede devolverlo de manera segura desde la función. Tienes que llamar a Dispose()
o ponerlo dentro de una cláusula using
porque implementa IDisposable.
Siempre pasaría la secuencia en la función. Esto le permite trabajar con cualquier flujo de la elección de la persona que llama, por ejemplo, directamente en un archivo sin ningún almacenamiento en búfer.
Tu segundo es mejor. Siempre trato de evitar la mutación de objetos dentro de las funciones si es posible.
Yo preferiría la forma inyectada. Elimina el acoplamiento directo entre su código y MemoryStream y lo hace más comprobable.
public void Foo(Stream stream)
{
stream.Write(somebuffer, 0, somebuffer.Length);
}
Ahora puedo probar Foo con cualquier clase que implemente Stream incluyendo una clase falsa.
Típicamente, haría la inyección en el constructor de la clase en lugar de hacerlo en métodos individuales, pero la idea es básicamente la misma.
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 );
}
}
Pasar una secuencia de memoria a una función y devolver una secuencia de memoria para una función no debe usarse indistintamente. Los métodos que describes sirven para dos propósitos diferentes.
Pasarle algo a una función es para cuando quiere que la función haga algo con el parámetro.
Devolver algo de una función es cuando se supone que la persona que llama debe hacer algo con el resultado.
Estás hablando de dos cosas diferentes, manzanas y naranjas.