2010-03-19 83 views
11

我正在試驗DynamicObject。我試圖做的事情之一是設置參數值ref/out,如下面的代碼所示。但是,我無法正確設置ij的值Main()(即使它們在TryInvokeMember()中設置正確)。有誰知道如何用ref/out參數調用DynamicObject對象,並且能夠檢索方法內設置的值?C#4.0'動態'不設置參考/輸出參數

class Program 
{ 
    static void Main(string[] args) 
    { 
     dynamic proxy = new Proxy(new Target()); 
     int i = 10; 
     int j = 20; 
     proxy.Wrap(ref i, ref j); 
     Console.WriteLine(i + ":" + j); // Print "10:20" while expect "20:10" 
    } 
} 

class Proxy : DynamicObject 
{ 
    private readonly Target target; 

    public Proxy(Target target) 
    { 
     this.target = target; 
    } 

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) 
    { 
     int i = (int) args[0]; 
     int j = (int) args[1]; 
     target.Swap(ref i, ref j); 
     args[0] = i; 
     args[1] = j; 
     result = null; 
     return true; 
    } 
} 

class Target 
{ 
    public void Swap(ref int i, ref int j) 
    { 
     int tmp = i; 
     i = j; 
     j = tmp; 
    } 
} 

更新7/15: 微軟聲稱已經解決了這一問題,爲下一個版本的.NET http://connect.microsoft.com/VisualStudio/feedback/details/543101/net-4-0s-dynamicobject-doesn-t-set-ref-out-arguments

更新2012年9月8日: 用VS.NET 2012測試與.NET 4.0和4.5,確認:它已經修復。

+0

完全重複:http:// stackoverflow。com/questions/2268857/c-4-determining-parameter-passing-semantics-in-dynamic-calls – Gabe 2010-03-19 06:21:00

+0

@gabe:實際上我看到了這個問題,但是問題是關於是否可以知道一個參數是否可以被稱爲通過ref/out或不通過,這與我在這裏要求的完全不同。我對此並不感興趣,因爲我可以對「目標」類進行一些思考。 – 2010-03-19 06:27:43

+0

儘管你的問題是不同的,那麼答案就包括你的問題的答案:* DynamicObject是「按值調用」* – Gabe 2010-03-19 07:16:59

回答

5

這看起來像可能是一個錯誤 - 可能在DynamicObject。如果添加Wrap方法Proxy這樣的:

public void Wrap(ref int x, ref int y) 
{ 
    target.Swap(ref x, ref y); 
} 

那麼即使這仍是動態調用(即Main代碼保持不變)代碼工作......所以至少一般的「如何做動態對象工作「層支持通過引用。

我懷疑,如果這確實在DLR的錯誤,它可能爲時已晚修爲.NET 4 - 但它是值得的Connect報告反正所以它可以固定在一個服務包。另外,如果這是一個有意的限制/限制,它應該在MSDN中清楚地記錄下來(目前爲止,據我所知)。

+0

有趣的解決方法,謝謝。這是很好的知道,但顯然我不會訴諸DynamicObject,如果我必須實現每個轉發方法:)。根據您的建議,我已向Connect提交了一份錯誤報告。 – 2010-03-19 07:01:22

+0

我不明白它可能是一個錯誤,因爲它不可能工作。 'TryInvokeMember'爲參數提供一個對象數組。爲了將整數放入數組中,必須將它們複製出來。唯一的辦法可能是半工作,如果動態綁定器複製引用一旦調用完成後從原始的args數組返回,但這只是模擬引用參數。 – Gabe 2010-03-19 07:21:06

+1

@gabe:當你使用反射調用ref參數的方法時,它就是這樣工作的 - 正如我所說的,它在靜態提供方法時工作,即使它仍然被*動態調用。換句話說,它在DynamicMetaObject級別工作。當然,與通過引用傳遞「真實」(例如,在方法調用本身期間變量將被解除關聯)相比,它會有一些扭曲,但對於99%的情況我確信它無關緊要。這感覺就像忽略這樣一個事實,即它們完全是參考參數,就像現在這樣。 – 2010-03-19 07:27:36

2

長話短說,動態對象不支持傳遞引用,所以你想要做的並不是直接可能的。

5

這不是一個錯誤。正如這裏所說的,DynamicObject不支持TryInvokeMember中的ref和out參數。傳遞給這個方法的所有東西都被「按價值」處理。不久,TryInvokeMember方法簡單地忽略了這些關鍵字,這就是爲什麼你的方法不起作用。

如果您按照Jon Skeet的建議在DynamicObject繼承的類中創建自己的Wrap方法,這將會有點不同。 工作流程如下所示:當有一個方法調用DynamicObject時,C#運行時綁定器會首先在類本身中查找該方法。如果它能找到它,它會調用這個方法。此時,關於「ref」和「out」參數的信息仍然保留。如果它找不到這樣的方法,它會調用TryInvokeMember方法,並簡單地拋出關於「ref」和「out」關鍵字的信息,並開始將「every」視爲「按值」。請記住,DynamicObject必須支持與其他語言的互操作性,其他語言可能不具備所有C#功能。

確實,關於「ref」和「out」的信息現在缺少文檔。我將把它添加到下一個文檔更新中。

+0

好的信息,謝謝!但是,儘管DynamicObject不應該爲ref/out提供互操作性,但是TryInvokeMember的調用者(根據我的理解,它是C#綁定器)應該會打擾並嘗試根據內部的args數組設置out/ref TryInvokeMember。難道不是嗎?不應該嗎? – 2010-04-03 07:20:00