2009-02-02 4 views
22

의견에서 새로 할당 된 메모리 스트림을 함수에서 반환하거나 함수로 전달하는 것이 더 좋습니까? 예를 들어,함수에서 메모리 스트림 반환하기

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; 
} 
+2

여기에는 많은 좋은 대답이 있지만 두 번째 형식에 대해 VS 2010에서 CA2000 안정성 경고를 제공하는 이유는 모두 다룹니다. 반환하려는 객체를 잘 처리 할 수 ​​없으며, 반환 된 객체를 처리하는 것은 어색한 것으로 보입니다. 첫 번째 양식이 더 바람직하다고 생각하게 만듭니다. –

답변

17

이것은 메서드에서 문자열을 반환하거나 StringBuilder를 추가해야하는지 여부와 같은 질문입니다. 대답은 사용 사례가 무엇인지에 따라 다릅니다.

호출자가 일부 데이터가 포함 된 기존 스트림으로 메소드를 호출하려고 할 가능성이 있습니까? 같은 스트림을 사용하여 여러 번 호출하려고 할 수 있습니까? 그렇다면 MemoryStream을 사용하는 버전이 더 효율적입니다. 반면에 데이터를 한 번만 원한다면 MemoryStream (또는 더 간단하게 바이트 배열)로 반환하는 것이 더 적절할 수 있습니다.

불행히도 설명에서 우리는 실제로 어떤 일이 일어 났는지 말할 수 없습니다. 물론 두 가지를 오버로드로 구현하고 다른 오버로드로 호출 할 수 있습니다.

2

는 안전하게 함수에서 반환 할 수 있습니다. Dispose()으로 전화하거나 IDisposable을 구현하기 때문에 using 절 안에 넣어야합니다.

+3

MemoryStream에서 Dispose를 호출해도 아무런 변화가 없습니다. 관리되지 않는 자원은 확보하지 않습니다. –

+1

+1 Mehrdad 님의 댓글 1 개. –

+1

@Merhdad & Jon - 항상 그렇지는 않습니다. 스트림에서 비동기 메서드를 사용했다면 WaitHandle을 캐싱 할 것이고 Dispose 메서드는 무언가를 수행합니다. 따라서 비동기 메서드가 호출되지 않았거나 호출되지 않는 한이를 처리하는 것이 더 안전합니다. –

1

두 번째 것이 좋습니다. 가능하다면 항상 함수 내에서 돌연변이를 피하려고 노력합니다.

+0

스트림은 변형 된 * supossed *이므로 스트림이면서 변경 불가능한 배열이 아닙니다. 그리고 Save, Export 또는 WriteXXX 메서드에 스트림을 전달하는 것은 꽤 일반적입니다. –

+0

+1에 대한 Pop의 설명 –

+0

돌연변이가 예상되는 많은 개체가 있습니다. 그러나 함수에서 객체를 완전히 초기화하려는 경우 함수가 참조를 제공하지 않고 객체에 대한 참조를 반환하지 않는 이유는 무엇입니까? –

0

두 가지 차이점이 많지 않습니다. 첫 번째 인스턴스에서 호출자는 메모리 스트림을 통해 제어 할 것이며, 두 번째 인스턴스에서는 다음과 같이 수행 할 수 있습니다

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

가장 중요한 것은 올바르게 폐기하는 것을 기억하는 것입니다.

+1

MemoryStream은 순전히 관리 객체입니다. 폐기 처분은 아무 것도하지 않습니다. –

+3

@Merhdad - 항상 그렇지는 않습니다. 스트림에서 비동기 메서드를 사용했다면 WaitHandle을 캐싱 할 것이고 Dispose 메서드는 무언가를 수행합니다. 따라서 비동기 메서드가 호출되지 않았거나 호출되지 않는 한이를 처리하는 것이 더 안전합니다. –

7

메모리 스트림을 함수에 전달하고 을 반환하는 경우 함수의 메모리 스트림을 서로 바꾸어서는 안됩니다. 설명하는 방법은 두 가지 다른 목적을 제공합니다.

  • 함수에 무언가를 전달하는 것은 함수가 매개 변수로 무언가를 수행하게하려는 경우입니다.

  • 함수에서 무엇인가를 반환하는 것은 호출자가 결과로 무엇인가를해야하는 경우입니다.

당신은 두 가지 다른 것들, 사과, 오렌지에 대해 이야기하고 있습니다.

3

항상 스트림을 함수에 전달합니다. 이를 통해 호출자가 선택한 모든 스트림 (예 : 버퍼링없이 파일로 바로 전송)에 대한 작업을 수행 할 수 있습니다.

+0

그러면 어떻게 많은 스트림이 스트림을 반환합니까? ;-) 일반적으로 Open ... 또는 GetStream이라는 이름이 붙어 있습니다. 스트림의 목적이 무엇인지에 달려 있다고 생각합니다. –

+1

그것은 ** 열기 **/** 스트림 만들기 **입니다. 메소드가 스트림을 작성하는지 또는 데이터를 스트림으로 푸시하는지 여부는 명확하지 않습니다. 두 가지는 서로 다른 해답을 가지고 있습니다. –

0

나는 주사 형태를 선호합니다. 그것은 당신의 코드와 MemoryStream 사이의 직접적인 연결을 제거하고 더 테스트 할 수 있습니다.

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

이제 모의 수업을 포함하여 스트림을 구현하는 모든 클래스로 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); 
    } 
} 
0

나는 두 가지 이유 때문에 처음으로 경향이있다 : "소유"사람의

  1. 의미를 메모리 스트림은 명확하다. 발신자가 생성 했으므로 호출자가 제거합니다 (관리되지 않는 리소스를 보유하는 다른 유형의 스트림에 더 많은 문제가 있음).
  2. Foo은 다음에서 작동하는 다른 방법과 함께 사용할 수 있습니다. 스트림
  3. Foo의 주요 목적은 (등 File.Open, 같은 유사) MemoryStreams의 팩토리 방법으로 경우 말했다

는, 두 번째 방법은 더 의미가 있습니다.

1

더 많은 생각을 한 후에는 Foo 메서드의 의도 된 의미로 생각됩니다. 그것은인가 :

  • 스트림을 생성하는 작업 (예 : File.Open().)
  • 스트림을 수정하는 작업 (예 : something.WriteXml().)

대답은 "스트림을 생성"하는 경우, 그것은 스트림을 반환합니다. 스트림을 수정하는 경우 스트림을 전달하십시오.

답변이 "some both of"인 경우 메소드가 하나의 책임을 갖도록 분할하는 것이 좋습니다.

0

스트림은 명시 적 처리 (메모리, 파일, 네트워크)가 필요한 리소스이므로 처리를 위해 RAII 방식을 적용하는 것이 가장 좋습니다. 즉, 함수를 초기화하는 함수는 릴리스에 대한 책임이 있어야 함을 의미합니다 (C#에서 keyord를 사용하고 있습니다). 이 패턴을 활성화하려면 스트림을 매개 변수로 수락한다고 말합니다. 그렇게하면 호출자는 스트림을 만들고 처리 할시기를 결정할 수 있습니다. 그 동안 스트림 메소드를 받아 들일 수 있습니다. MemoryStream에서만 작동해야하는 것처럼 보이지 않습니다.