2010-04-05 2 views
5

이미지를 전송하는 장치로 작업하고 있으며 이미지를 요청할 때 이미지 데이터 이전에 문서화되지 않은 정보가 있습니다. 필자는 바이너리 데이터를보고 내부의 이미지 헤더 정보를 확인함으로써이 사실을 깨달을 수있었습니다.바이트 배열의 확장 메소드에 문제가 있음

나는 원래 정상적인 방법을 사용했고 확장 방법으로 변환했다. 여기서 원래의 질문은 배열을 첫 번째 매개 변수로 가지지 않는다고 불평하는 컴파일러와 관련이 있습니다 (Byte []를 가졌음). 그러나 오류가 발생하여 호출 코드에서 첫 번째 인수를 삭제하는 것을 잊어 버렸습니다. 즉, 내가 가진 데 사용 :

어쨌든
buffer.RemoveUpToByteArray(buffer, new byte[] { 0x42, 0x4D }); 

, 즉 내가 있었다 나는 내 실수를 깨달았 때문에 모두가 지금은 고정입니다 :

Byte[] new_buffer = RemoveUpToByteArray(buffer, new byte[] { 0x42, 0x4D }); 

및 확장 방법을 변경 한 후, 내가 잘못 사용했다

SO에 코드 예제를 입력하십시오. 그러나 확장 메서드 및 참조와 값 형식에 대한 이해가 부족하다는 새로운 문제가 있습니다. 코드는 다음과 같습니다.

public static void RemoveFromByteArrayUntil(this Byte[] array, Byte[] until) 
{ 
    Debug.Assert(until.Count() > 0); 
    int num_header_bytes = until.Count(); 
    int header_start_pos = 0; // the position of the header bytes, defined by [until] 
    byte first_header_byte = until[0]; 
    while(header_start_pos != -1) { 
     header_start_pos = Array.IndexOf(array, first_header_byte, header_start_pos); 
     if(header_start_pos == -1) 
      break; 
     // if we get here, then we've found the first header byte, and we need to look 
     // for the next ones sequentially 
     for(int header_ctr=1; header_ctr<num_header_bytes; header_ctr++) { 
      // we're going to loop over each of the header bytes, but will 
      // bail out of this loop if there isn't a match 
      if(array[header_start_pos + header_ctr] != until[header_ctr]) { 
       // no match, so bail out. but before doing that, advance 
       // header_start_pos so the outer loop won't find the same 
       // occurrence of the first header byte over and over again 
       header_start_pos++; 
       break; 
      } 
     } 
     // if we get here, we've found the header! 
     // create a new byte array of the new size 
     int new_size = array.Count() - header_start_pos; 
     byte[] output_array = new byte[new_size]; 
     Array.Copy(array, header_start_pos, output_array, 0, new_size); 
     // here is my problem -- I want to change what array points to, but 
     // when this code returns, array goes back to its original value, which 
     // leads me to believe that the first argument is passed by value. 
     array = output_array; 
     return; 
    } 
    // if we get here, we didn't find a header, so throw an exception 
    throw new HeaderNotInByteArrayException(); 
} 

내 문제는 이제 확장 메서드에 대한이 인수가 값으로 전달된다는 것입니다. 어떤 배열 포인트를 재 할당하고 싶지만,이 경우 배열의 데이터를 대신 조작해야하는 것처럼 보입니다.

+1

답이 아니라 단지 관찰 : RemoveUpToByteArray가 호출 될 때마다 새 바이트 배열을 만들어야하는 것으로 보입니다. 배열의 인덱스로 정수를 사용하면 읽은 거리를 추적하는 것이 더 효율적입니다. –

+0

@Dave : 컴파일러 오류가 발생하는 곳이 너무 구체적이지 않습니다. 나는 그것이 * 호출 사이트 *에서이고 확장 메서드가 아닌 것으로 추측하고 있습니다. 그것이 맞다하더라도, 당신은 어느 쪽의 코드도 보이지 않는다. 바이트 배열에 대한 확장 메서드를 만들고 쉽게 실행할 수 있으므로 대답을 얻기 위해이 부분을 처리해야합니다. – casperOne

+0

확인, 문제 없습니다! * 실제 * 코드를 게시하겠습니다. :) 의견을 보내 주셔서 감사합니다. – Dave

답변

5

확장 메서드는 인스턴스 메서드로만 보이는 정적 메서드입니다. 확장 메서드가 작업중인 인스턴스를 값으로 읽기 전용으로 간주 할 수 있습니다. 확장의 첫 번째 매개 변수 인 byte []의 인스턴스 메서드에 할당하면 작동하지 않습니다.

buffer = buffer.RemoveUpToByteArray(header); 

이 확장 바이트 배열 결과를 반환 확인하고 버퍼 할당하려고하지 않습니다 다음과 같은 과제를 쓰기 당신은 할당에서 멀리 얻을 수 없습니다,하지만 당신은 당신의 확장을 수정할 수 있습니다 확장자 내에서. 확장 기능은 다음과 같습니다.

public static class MyExtensionMethods 
{ 
    public static byte[] RemoveUpToByteArray(this byte[] buffer, byte[] header) 
    { 
     byte[] result = buffer; 

     // your logic to remove header from result 

     return result; 
    } 
} 

이 정보가 도움이되기를 바랍니다.

편집 : 위는 값 유형에만 맞습니다. 확장하는 유형이 참조 유형 인 경우 위에 수행하려고하는 것과 같은 유형에서 직접 작동하는 문제가 없습니다. 슬프게도 바이트 배열은 struct이므로 System.ValueType에서 파생됩니다. 확장 내부에 완벽하게 합법적 될 것이다 다음 사항을 고려하고 원하는 결과를 줄 것이다 : [확실하게 확인을

public class MyBytes 
{ 
    public byte[] ByteArray { get; set; } 
} 

public static class MyExtensionMethods 
{ 
    // Notice the void return here... 
    public static void MyClassExtension(this MyBytes buffer, byte[] header) 
    { 
     buffer.ByteArray = header; 
    } 
} 
+0

나는 조금 더 나은 것을 좋아하는 또 다른 해결책을 가지고있다 ... 나는 이제 내 질문에 넣을 것이다. – Dave

+0

나는 그 말을 되 돌리며 나는 네가 옳다고 생각한다. 나는 다른 선택권이 없다. – Dave

+0

이미 생성 한 클래스에서 확장 메서드를 정의하는 요점은 무엇입니까? 'MYBytes' 내부의 메소드가 그 일을합니다. –

1

나는 당신이 발생하거나 해결 방법에있다 구체적으로 어떤 문제가 모르는 것이 유감을 네임 스페이스가 참조되고 비슷하게 명명 된 메서드와의 충돌을 해결하는 것은 시작이다.] 그러나 나는 하나 또는 두 개의 기이를 느꼈다.

using System.Linq; 
namespace Sample.Extensions 
{ 
    public static class ByteExtensions 
    { 
     public static void RemoveHeader (this byte[] buffer, byte[] header) 
     { 
      // take first sequence of bytes, compare to header, if header 
      // is present, return only content 
      // 
      // NOTE: Take, SequenceEqual, and Skip are standard Linq extensions 
      if (buffer.Take (header.Length).SequenceEqual (header)) 
      { 
       buffer = buffer.Skip (header.Length).ToArray(); 
      } 
     } 
    } 
} 

이 컴파일 및 VS2010RC에서 실행, 다음 샘플 솔루션을 고려해야합니다., 사용법을 설명하기 위해

using Sample.Extensions; 
namespace Sample 
{ 
    class Program 
    { 
     static void Main (string[] args) 
     { 
      byte[] buffer = new byte[] { 00, 01, 02 }; 
      byte[] header = new byte[] { 00, 01 }; 
      buffer.RemoveHeader (header); 

      // hm, so everything compiles and runs, but buffer == { 00, 01, 02 } 
     } 
    } 
} 

그래서 우리는 컴파일을 수신하거나 런타임 오류하지만 의도 한대로 명확하게 작동하지 않습니다하지 않습니다. 이는 확장이 여전히 표준 메소드 의미론을 준수해야하므로 매개 변수가 값에 의해 전달된다는 의미입니다. 새 배열을 가리 키도록 buffer을 변경할 수 없습니다.

우리는

public static byte[] RemoveHeaderFunction (this byte[] buffer, byte[] header) 
{ 
    byte[] stripped = null; 
    if (stripped.Take (header.Length).SequenceEqual (header)) 
    { 
     stripped = stripped.Skip (header.Length).ToArray(); 
    } 
    else 
    { 
     stripped = buffer.ToArray(); 
    } 
    return stripped; 
} 

지금
using Sample.Extensions; 
namespace Sample 
{ 
    class Program 
    { 
     static void Main (string[] args) 
     { 
      byte[] buffer = new byte[] { 00, 01, 02 }; 
      byte[] header = new byte[] { 00, 01 }; 

      // old way, buffer will still contain { 00, 01, 02 } 
      buffer.RemoveHeader (header); 

      // new way! as a function, we obtain new array of { 02 } 
      byte[] stripped = buffer.RemoveHeaderFunction (header); 
     } 
    } 
} 

불행하게도, 배열 [잘못이 용어를 사용하고있을 수 있습니다] 불변 값 종류, 기존 기능의 의미에 우리의 방법을 다시 작성하여이 문제를 해결할 수 있습니다. "배열"을 내부에서 수정하는 유일한 방법은 컨테이너를 변경 가능한 참조 유형 (예 : List<byte>)으로 변경하는 것입니다.

는 "심판에 의해 통과"에 정말 예민한 경우에 장소, 부작용의 의미는 다음 하나의 옵션은 사용에 관해서는 다음과 같은

using System.Linq; 
namespace Sample.Extensions 
{ 
    public static class ListExtensions 
    { 
     public static void RemoveHeader<T> (this List<T> list, List<T> header) 
     { 
      if (list.Take (header.Count).SequenceEqual (header)) 
      { 
       list.RemoveRange (0, header.Count); 
      } 
     } 
    } 
} 

될 수

static void Main (string[] args) 
{ 
    byte[] buffer = new byte[] { 00, 01, 02 }; 
    byte[] header = new byte[] { 00, 01 }; 

    List<byte> bufferList = buffer.ToList(); 

    // in-place side-effect header removal 
    bufferList.RemoveHeader (header.ToList()); 
} 

후드 아래에서 List<T>T 유형의 배열을 유지 관리합니다. 특정 임계 값에서는 단순히 기본 배열을 조작하고 \ 또는 새 배열을 인스턴스화합니다.

희망이 도움이됩니다. :)

+0

고마워, 조니. Audie도 같은 결론에 도달했습니다 ... 첫 번째 매개 변수를 참조로 전달할 수 있었으면 좋겠습니다. 예를 들어 'ref'를 'this'와 함께 사용할 수없는 이유는 무엇입니까? – Dave

관련 문제