2016-01-10 34 views
0

我有一個DynamicObject的子類,其中我實現了幾個隱式操作符(用於自動轉換)並覆蓋了一些Try [OperationType]方法。在DynamicObject上添加操作

當我嘗試使用該類型的對象(問題底部的異常)進行添加(+)操作時,出現異常。

... 
var d = GetDynamicObject(); 
int result = d + 1; 
... 

一個答案,我認爲這將有助於這個問題is this one。描述的行爲是正確的,但我的動態對象有幾個靜態隱式操作符定義,我認爲問題是與字符串之一。 當我爲字符串定義隱式運算符時,que add(+)操作會引發異常。 我可以通過堆棧跟蹤觀察問題可能是他無法綁定運算符,並且我開始認爲這是因爲某種添加/級聯混淆。

我簡化了我的代碼,並寫了這個測試,我認爲它描繪了這種情況。 當我評論字符串的隱式運算符時,eveything效果很好。

我做錯了什麼?有一些我需要重寫的方法嗎? 任何想法?

public class Program 
{ 
    static void Main(string[] args) 
    { 
     try 
     { 
      var d = GetDynamicObject(); 
      int result = d + 1; 
      Console.WriteLine("OK: " + result); 
     } 
     catch (Exception) 
     { 
      Console.WriteLine("Error!"); 
     } 

     Console.ReadLine(); 
    } 

    public static dynamic GetDynamicObject() 
    { 
     return new MyDynamicObject(); 
    } 
} 


public class MyDynamicObject : DynamicObject 
{ 
    public static implicit operator int(MyDynamicObject obj) 
    { 
     return 0; 
    } 

    public static implicit operator long(MyDynamicObject obj) 
    { 
     return 0; 
    } 

    public static implicit operator double(MyDynamicObject obj) 
    { 
     return 0; 
    } 

    // Works when commented 
    public static implicit operator string(MyDynamicObject obj) 
    { 
     return null; 
    } 

    public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result) 
    { 
     Console.WriteLine("MyDynamicObject.TryBinaryOperation"); 
     return base.TryBinaryOperation(binder, arg, out result); 
    } 
} 

例外:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderInternalCompilerException was unhandled 
    HResult=-2146233088 
    Message=An unexpected exception occurred while binding a dynamic operation 
    Source=Microsoft.CSharp 
    StackTrace: 
     at Microsoft.CSharp.RuntimeBinder.Semantics.ExpressionBinder.WhichSimpleConversionIsBetter(PredefinedType pt1, PredefinedType pt2) 
     at Microsoft.CSharp.RuntimeBinder.Semantics.ExpressionBinder.WhichTypeIsBetter(PredefinedType pt1, PredefinedType pt2, CType typeGiven) 
     at Microsoft.CSharp.RuntimeBinder.Semantics.ExpressionBinder.WhichBofsIsBetter(BinOpFullSig bofs1, BinOpFullSig bofs2, CType type1, CType type2) 
     at Microsoft.CSharp.RuntimeBinder.Semantics.ExpressionBinder.FindBestSignatureInList(List`1 binopSignatures, BinOpArgInfo info) 
     at Microsoft.CSharp.RuntimeBinder.Semantics.ExpressionBinder.BindStandardBinop(ExpressionKind ek, EXPR arg1, EXPR arg2) 
     at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.BindBinaryOperation(CSharpBinaryOperationBinder payload, ArgumentObject[] arguments, Dictionary`2 dictionary) 
     at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.DispatchPayload(DynamicMetaObjectBinder payload, ArgumentObject[] arguments, Dictionary`2 dictionary) 
     at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.BindCore(DynamicMetaObjectBinder payload, IEnumerable`1 parameters, DynamicMetaObject[] args, DynamicMetaObject& deferredBinding) 
     at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.Bind(DynamicMetaObjectBinder payload, IEnumerable`1 parameters, DynamicMetaObject[] args, DynamicMetaObject& deferredBinding) 
     at Microsoft.CSharp.RuntimeBinder.BinderHelper.Bind(DynamicMetaObjectBinder action, RuntimeBinder binder, IEnumerable`1 args, IEnumerable`1 arginfos, DynamicMetaObject onBindingError) 
     at Microsoft.CSharp.RuntimeBinder.CSharpBinaryOperationBinder.FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg, DynamicMetaObject errorSuggestion) 
     at System.Dynamic.DynamicObject.MetaDynamic.<>c__DisplayClass9_0.<BindBinaryOperation>b__0(DynamicMetaObject e) 
     at System.Dynamic.DynamicObject.MetaDynamic.CallMethodWithResult(String methodName, DynamicMetaObjectBinder binder, Expression[] args, Fallback fallback, Fallback fallbackInvoke) 
     at System.Dynamic.DynamicObject.MetaDynamic.BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg) 
     at System.Dynamic.BinaryOperationBinder.Bind(DynamicMetaObject target, DynamicMetaObject[] args) 
     at System.Dynamic.DynamicMetaObjectBinder.Bind(Object[] args, ReadOnlyCollection`1 parameters, LabelTarget returnLabel) 
     at System.Runtime.CompilerServices.CallSiteBinder.BindCore[T](CallSite`1 site, Object[] args) 
     at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1) 
     at WIG.Common.Tests.Program.Main(String[] args) in C:\WIG\WIG Framework\Dev\WIG.Common.Tests\Program.cs:line 74 
     at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) 
     at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) 
     at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 
     at System.Threading.ThreadHelper.ThreadStart_Context(Object state) 
     at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
     at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
     at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
     at System.Threading.ThreadHelper.ThreadStart() 
    InnerException: 
+0

嘗試顯式地將對象轉換爲像這樣的int:int result =(int)d + 1;' –

+0

謝謝。是的,這工作,我忘了提及,我已經嘗試了明確的演員,並且工作。這是我懷疑問題與運行時表達式(操作,操作數,類型...)的解析有關的原因之一。 我想爲MyDynamicObject的用戶忽略類型轉換,定義對象本身的所有行爲(讓他像使用動態一樣使用對象)。爲此,我可以訪問的是隱式轉換器和虛擬的'DynamicObject'方法。 也許我正面臨着RuntimeBinder或其他組件的限制。 –

回答

0

這是a bug in the framework(編輯:Fixed in the corefx codebase,所以.NET核心2.0.4或更高不應該看到這個問題)。我們可以看到同樣的事情發生dynmicDynamicObject

public class Castable 
{ 
    public static implicit operator int(Castable obj) => 3; 

    public static implicit operator string(Castable obj) => "abc"; 
} 

… 

dynamic d = new Castable(); 
var result = d + 2; // Throws RuntimeBinderInternalCompilerException in NetFX 
         // IndexOutOfRangeException in CoreFX. 

變化dynamicvar和靜態綁定工作動態的,而不是和(沒有這個bug)設置result5。註釋掉轉換操作符和動態聯編程序可以使用其他罰款。

問題是,解決與+一起使用哪種轉換(作爲內置運算符用於添加和字符串連接)的處理遇到了偏離錯誤。

正如你所知1 + 2被視爲一個添加和"abc" + x被視爲string.Concat("abc", x)。在d + 1的情況下,ddynamic,活頁夾需要找出使用哪一個。

當比較可能性時,在表格中查找一些「簡單」目標類型。如果這是可能的,那麼這個目標的枚舉值將低於一個給定的值,所以顯然,首先要做的是看看是否是這種情況。

但不幸的是,檢查使用<=而不是<,但比較的限制是比允許的最高一個,所以<將是正確的。剛剛超過極限值恰好是string。因此,如果您將動態聯編程序放在轉換爲「簡單」類型和轉換爲字符串之間進行選擇的情況下,它會決定它可以將兩種可能性作爲「簡單」進行比較,嘗試在索引超出數組範圍的查找表。根據版本的不同,它會與IndexOutOfRangeException混淆,或者它會觸發一個斷言以確保它沒有正在做它正在做的事情,並且與RuntimeBinderInternalCompilerException一起爆炸。