2011-03-24 39 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#球隊無人問津指針或具有新功能的不安全的代碼交互。而相關的文檔是完全無益的。 – 2011-03-24 12:09:13

+2

我的猜測是該問題的基礎是csharp規範的25.1.1節,並澄清了後者「在不安全的代碼(§27)中,類型參數不應該是指針類型」,因爲DLR在內部使用表達式樹在某些時候很多表達式>可能不得不被創建,並且它不起作用。 – 2011-03-24 12:26:25

+0

@Virtual - 你指的是哪個版本的規範?我正在尋找4.0,其部分似乎只上升到18. – 2011-03-24 12:54:48

回答

4

來自該錯誤信息的文本是我自己的,故事是你不能混合指針類型和動態調度,句號。爲什麼?

潛在的原因是指針不能被裝箱。它們不能用作類型參數的事實有點像紅鯡魚,因爲我們完全可以將「ref」類型作爲動態參數,而且它們也不能用作類型參數。編譯器發出新的委託類型來處理ref類型,它可能會這樣做,以便在您的程序集中生成代碼,以便根據具有指針類型參數的簽名創建調用站點。

但回到問題。由於指針不能被裝箱,所以你永遠不能在「動態」中擁有一個指針值,這意味着你永遠不能真正動態指派指針。另外,由於動態調用的返回值是裝箱的,因此不能動態調度到返回指針的函數。

因此,從某種意義上講,您可以將此視爲簡化用戶問題的決策之一。說起來有點複雜,好的,這裏有幾件事情可以用指針和動態來做,而且有一些事情可能會讓你放棄一段時間,所以儘量讓它們保持直線。說出(並記住)「更容易,」根本沒有動態指針。「

還有一個問題,我不得不承認我的記憶有點模糊,即使我們確實允許你這樣做,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委託類型綁定,但我需要清楚地閱讀更多內容。關於拳擊和盒裝指針,它可以用一個標記類型來解決,比如int **和boxing的指針,但是其複雜性/成本很高(例如,什麼安全漏洞或者它可能包含在silverlight中的潛在問題...)。再次抱歉,針對csharp團隊的評論我沒有意識到我聽起來如此苛刻。 – 2011-03-24 23:41:52

+0

不能'IntPtr'用於指針的裝箱嗎? – 2012-02-29 00:30:08

+0

本,是的,有任意數量的策略,可以用它來獲得在堆上,包括拳擊一個IntPtr指針值,但這並不改變的事實,你不能框的指針。反正這些東西,如果你做一個,那麼你已經崩潰了一些用戶的意圖,如用戶是否想要做的事情有一個IntPtr或用指針。然後,你需要更多的機制來確定其是,在代碼中,這可能不總是甚至有可能(什麼調用現場瞭解的返回值?)。這一切都非常複雜,正如我所說,這種情況並不是一個高度優先的事情。 – 2012-03-02 09:06:18

1

錯誤消息強烈表明方法根本不起作用。您可能必須使用靜態綁定(可能是聲明void GetDatas(byte *buffer, uint *count)的接口)或手動反射。

+0

這似乎是完全可能的,但它會很高興有某種支持文檔SOMEWHERE解釋此限制:\ – GWLlosa 2011-03-24 11:42:42

3

如在我的評論指定我的猜測是,該問題的基礎是CSHARP規範的章節25.1.1和澄清後者

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

作爲DLR內部使用表達式樹很多在一些點的可能不得不創建Expression<Action<byte*, uint*>>,它將無法工作。


我重複我的評論這裏只是爲了能夠發佈一些代碼,作爲解決方案之一可能是使用的IntPtr。它的作品,但你失去了部分類型信息,所以我不知道它是否真的有用。

它可以避免丟失類型安全創建一個IntPtr<T>結構可能允許使用動態,在這種情況下,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) 
    { 

    } 
} 
相關問題