2011-03-24 4 views
2

다음과 같은 코드가 있습니다.오류 CS1978 : 동적으로 발송되는 작업에 대한 인수로 'uint *'유형의 표현식을 사용할 수 없습니다.

 public void GetData(dynamic dObj) 
    { 
     unsafe 
     { 
      byte[] myBuffer = new byte[255]; 
      uint myBufferCount = 0; 
      fixed (byte* myBufferPointer = myBuffer) 
      { 
       dObj.GetDatas(myBufferPointer, &myBufferCount); 
      } 
     } 
    } 

아이디어는 "GetDatas"라는 버퍼가 있고 포인터는 포인터로 사용되는 함수를 호출하는 것입니다. 그러나 다음 오류가 트리거됩니다.

Error CS1978: Cannot use an expression of type 'uint*' as an argument to a dynamically dispatched operation

이 오류 또는 해결 방법에 대한 추가 정보를 찾을 수 없습니다. MSDN 문서는이 오류 메시지를 전혀 포함하지 않는 것처럼 보이지 않으므로 도움이되지 않습니다. 여기서 뭐가 잘못 됐어? 어떻게 동적으로 서명이있는 함수를 호출합니까?

 void MyFunc(byte *buffer, uint *count); 

?

+0

기본적인 결론은 난에이 C#을 팀에 아무도 포인터 또는 새로운 기능 안전하지 않은 코드의 상호 작용에 대해 관심이 없다는 것입니다 온 . 그리고 관련 문서는 전혀 도움이되지 않습니다. –

+2

내 생각에 문제의 근본은 csharp 스펙의 섹션 25.1.1이며 DLR이 내부적으로 표현 트리를 사용하기 때문에 "안전하지 않은 코드 (type 277)에서 포인터 타입이 아닐 것" 어떤 시점에서 Expression >이 생성되어야 할 수도 있고 작동하지 않을 수도 있습니다. –

+0

@Virtual - 어떤 버전의 스펙을 참조하고 있습니까? 4.0에서 찾고 있는데 그 섹션은 최대 18 개까지만 보이는 것 같습니다. –

답변

4

오류 메시지의 텍스트는 제 자신이며, 포인터 유형과 동적 디스패치 기간을 섞어서 사용해서는 안됩니다. 왜?

근본적인 이유는 포인터를 박스 처리 할 수 ​​없다는 것입니다. 형식 인수로 사용할 수 없다는 사실은 약간의 붉은 청어입니다. 우리는 동적 인수로 "ref"형식을 사용할 수 있으며 유형 인수로도 사용할 수 없으므로 완벽합니다. 컴파일러는 ref 형식을 처리하기 위해 새 대리자 형식을 내고 포인터 형식 매개 변수가있는 서명에 대해 호출 사이트를 만드는 코드를 어셈블리에 생성 할 수 있습니다.

하지만 문제가 있습니다. 포인터는 boxed 될 수 없으므로 "동적"에 포인터 값을 가질 수 없습니다. 즉, 실제로 포인터를 동적으로 디스패치 할 수 없습니다. 또한 동적 호출의 반환 값은 박스로 처리되므로 포인터를 반환하는 함수에 동적으로 디스패치 할 수 없습니다.

한 가지면에서이 문제는 사용자 문제를 단순화하는 결정 중 하나로 생각할 수 있습니다. 그것은 말하기가 조금 복잡합니다. 좋아요, 여기 포인터와 다이내믹으로 할 수있는 몇 가지 사항이 있습니다. 잠시 동안 빠져 나갈 수있는 것들이 있으므로 똑바로 유지하십시오. 동적 인 포인터가 전혀 없다는 것을 기억하고 말하는 것이 훨씬 쉽습니다."

또 다른 문제가 있습니다. 내 기억이 약간 퍼지다는 것을 인정해야합니다. DLR이이를 허용해야한다고해도, C# 4.0을 구현할 때 DLR은 움직이는 표적이었습니다. 즉, DLR과 C# 런타임은 실제로 모두 움직이는 표적이었습니다. 여러 시점에서 여러 구성 요소 중 하나가 여러 가지 이유로 인수를 시도하고 있었지만, 선적 된 내용과 그 문제가 여전히 발생하는지 여부를 기억할 수 없습니다. 하지만 어쨌든 적어도 어느 시점에서는 이것이 고려 사항이었습니다.

"동적 인 경우 가끔 나타나는 포인터"는 다양한 팀이 매우 우선 순위라고 생각하지 않았던 기능입니다. 물론 물론 그렇습니다. 안전하지 않은 코드가 일반적으로 중요하다고 생각하지 않는다는 것을 의미하지는 않습니다.

편집 : 언어 사양에서 이에 대한 언급을 찾을 수 없습니다. 그것은 스펙 버그입니다. 보고가 있는지 확인하겠습니다.

는 편집 편집 : 역학과 함께 포인터를 사용하지 그러나 제네릭과 함께이를 사용하려고 한 적이 https://connect.microsoft.com/VisualStudio/feedback/details/653347/c-language-spec-ommission-cannot-mix-pointer-types-with-dynamic-dispatch

+0

ref 매개 변수로 동적 호출을 디 컴파일하고 예 해결책은 정말 간단합니다. 왜 그런지 모르겠습니다. DLR이 Action/Func 델리게이트 형식과 더 관련이 있다고 믿었지만이 점에 대해 더 자세히 읽어야합니다. 복싱과 박스형 포인터에 관해서는 마커 타입으로 Pointer > int **와 boxing으로 해결할 수 있지만 복잡성/비용은 높습니다 (예 : 실버 홀에 포함될 가능성이있는 보안 구멍 또는 잠재적 인 문제) ...). 다시 csharp 팀을 대상으로하는 제 의견에 대해 사과드립니다. 나는 너무 가혹하게 들렸다는 것을 깨닫지 못했습니다. –

+0

포인터의 복싱에'IntPtr'을 사용할 수 없습니까? –

+0

벤, 예, 상자에 IntPtr을 포함하여 힙에 포인터 값을 가져 오는 데 사용할 수있는 전략은 다양하지만 포인터를 지정할 수 없다는 사실은 바뀌지 않습니다. 어쨌든, 만약 당신이 이러한 것들 중 하나를한다면, 사용자가 IntPtr로 포인터를 사용하기를 원하는지, 포인터로 포인터를 사용하여 포인터를 사용하여 원하는지와 같은 사용자의 의도를 무너 뜨리게됩니다. 그리고 코드가 무엇인지 판단하기 위해 더 많은 메커니즘이 필요합니다. 항상 가능하지는 않습니다 (콜 사이트는 반환 값에 대해 무엇을 알고 있습니까?). 그것은 모두 너무 복잡하며, 내가 말했듯이이 시나리오는 최우선 순위는 아닙니다. –

1

오류 메시지는 접근법이 간단하게 작동하지 않을 것이라고 강력하게 제안합니다. 정적 바인딩 (아마도 void GetDatas(byte *buffer, uint *count)을 선언하는 인터페이스)이나 수동 리플렉션 중 하나를 사용해야 할 수도 있습니다. 내 댓글에 지정된 내 생각 엔 문제의 기본이 CSHARP 사양의 섹션 25.1.1이라고하고 후자 명확히으로

+0

그건 완전히 가능해 보이지만 어쨌든이 제한을 설명하는 일종의 지원 문서가있는 것이 좋을 것입니다 : \ – GWLlosa

3

In unsafe code (§27), a type-argument shall not be a pointer-type

DLR에 내부적으로 몇 가지 포인트가 AT 식 트리를 많이 사용하기 때문에 Expression<Action<byte*, uint*>>을 만들어야 할 수 있으며 작동하지 않을 수 있습니다.


난 그냥 솔루션 중 하나를 IntPtr를 사용할 수 있습니다로, 일부 코드를 게시 할 수 있도록 여기 내 코멘트를 반복했다. 그것은 작동하지만 형식 정보의 일부를 잃어 버리기 때문에 실제로 유용한 지 모릅니다.

struct가 다이나믹을 사용하도록 허용하는 형식 안전성을 잃지 않도록하십시오.이 경우 T 형은 DLR의 마커 일뿐입니다. 그러나 DLR을 포인터로 사용할 수 있으려면이 작업을 수행하는 것이 과도한 경우 일 수 있습니다.

void Main() 
{ 
    unsafe 
    { 
     var inst = new TestClass(); 
     byte* test = stackalloc byte[5]; 

     uint count; 
     inst.Test(test, &count); 
    } 

    unsafe 
    { 
     dynamic inst = new TestClass(); 
     byte* test = stackalloc byte[5]; 

     uint count; 
     inst.Test(new IntPtr(test), new IntPtr(&count)); 
    } 
} 

class TestClass 
{ 
    public unsafe void Test(IntPtr buffer, IntPtr count) 
    { 
     Test((byte*)buffer.ToPointer(), (uint*)count.ToPointer()); 
    } 

    public unsafe void Test(byte* buffer, uint* count) 
    { 

    } 
} 
관련 문제