Неявная типизация.NET вызывает исключение RuntimeBinder
Я работаю с API под названием ArcObjects и.NET 4.5. Я столкнулся с ошибкой
'object' does not contain a definition for 'AddValue'
при использовании одного из объектов API, но я думаю, что это может быть более общей проблемой.NET, чем с этим API. Это ошибка, которая возникает во время выполнения.
Для некоторого фона все объекты ArcObject являются COM-объектами, поэтому библиотеки.NET являются просто обертками вокруг них. При работе с ArcObjects я в основном работаю с базой геоданных, которая в основном представляет собой обычную RDBS (с пространственным компонентом), где каждая строка называется объектом.
Моя первая попытка кода была следующей:
//this IUniqueValueRenderer is an ArcObject
var uvRenderer = new ESRI.ArcGIS.Carto.UniqueValueRendererClass() as IUniqueValueRenderer;
//... set some parameters on the uvRenderer
//the error occurs on this line. SampleAreaFeature.get_Value(idIndex) returns the non-null integer 324
//SampleAreaFeature is a feature in the geodatabase
uvRenderer.AddValue(SampleAreaFeature.get_Value(1).ToString(), "SampleField", redSymbol as ISymbol);
Определение для AddValue является AddValue(string,string,ISymbol)
, Он компилируется без ошибок и предупреждений, и AddValue можно найти через Reflection во время выполнения.
Я смог обойти эту проблему, изменив мою последнюю строку следующим образом:
string value = SampleAreaFeature.get_Value(idIndex).ToString();
uvRenderer.AddValue(value, "SampleField", redSymbol as ISymbol);
Даже незнакомец следующее НЕ работает:
var value = SampleAreaFeature.get_Value(idIndex).ToString();
uvRenderer.AddValue(value, "SampleField", redSymbol as ISymbol);
И это подводит меня к проблеме. Почему эти три фрагмента собираются по-разному?
Значение, которое не указано явно, дает разные результаты, которые компилируются, но один из которых не может быть привязан к методу AddValue во время выполнения.
Вот IL для использования ключевого слова var:
IL_00bb: call class ESRI.ArcGIS.Geodatabase.IFeature DataReviewModule.ModGlobals::get_SampleAreaFeature()
IL_00c0: ldloc.2
IL_00c1: callvirt instance object ESRI.ArcGIS.Geodatabase.IFeature::get_Value(int32)
IL_00c6: callvirt instance !2 class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>::Invoke(!0, !1)
IL_00cb: stloc.3
IL_00cc: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`5<class [System.Core]System.Runtime.CompilerServices.CallSite, class [ESRI.ArcGIS.Carto]ESRI.ArcGIS.Carto.IUniqueValueRenderer, object, string, class ESRI.ArcGIS.Display.ISymbol>> DataReviewModule.docWinReview/'<>o__127'::'<>p__1'
IL_00d1: brtrue.s IL_0125
IL_00d3: ldc.i4 256
IL_00d8: ldstr "AddValue"
IL_00dd: ldnull
IL_00de: ldtoken DataReviewModule.docWinReview
IL_00e3: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_00e8: ldc.i4.4
IL_00e9: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
IL_00ee: dup
IL_00ef: ldc.i4.0
IL_00f0: ldc.i4.1
IL_00f1: ldnull
IL_00f2: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
IL_00f7: stelem.ref
А вот IL для использования ключевого слова 'string':
IL_00f5: call class ESRI.ArcGIS.Geodatabase.IFeature DataReviewModule.ModGlobals::get_SampleAreaFeature()
IL_00fa: ldloc.2
IL_00fb: callvirt instance object ESRI.ArcGIS.Geodatabase.IFeature::get_Value(int32)
IL_0100: callvirt instance !2 class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>::Invoke(!0, !1)
IL_0105: callvirt instance !2 class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, string>::Invoke(!0, !1)
IL_010a: stloc.3
IL_010b: ldloc.1
IL_010c: ldloc.3
IL_010d: ldsfld string DataReviewModule.ModGlobals::sampleIdField
IL_0112: ldarg.0
IL_0113: ldfld class ESRI.ArcGIS.Display.ISimpleFillSymbol DataReviewModule.docWinReview::redSymbol
IL_0118: isinst ESRI.ArcGIS.Display.ISymbol
IL_011d: callvirt instance void [ESRI.ArcGIS.Carto]ESRI.ArcGIS.Carto.IUniqueValueRenderer::AddValue(string, string, class ESRI.ArcGIS.Display.ISymbol)
1 ответ
SampleAreaFeature.get_Value(idIndex)
вернул динамику.
Это приводит к var value
быть типом dynamic
,
Есть какое-то правило о привязке COM, которое я не понимаю, что вызывает два определения AddValue
бороться здесь, что не приводит к динамическому разрешению. Разрешение COM-имен объединяет все интерфейсы для поиска имен, что избавило меня от неприятностей, но, похоже, у вас проблемы.
Также вполне возможно, что этот класс не поддерживает динамический вызов во время выполнения. Отражение выполняется для видимого типа, а динамический вызов - для реального типа. Если они не совпадают, происходят странные вещи, и у меня есть код, который зависит от них, чтобы работать вокруг интерфейса COM. Guid, который дублировался (один пользователь - MS-Word, и я не знаю, кто другой). Если реальный тип не поддерживает динамическое разрешение, это будет ожидаемой ошибкой.
Лично я бы порекомендовал исправить это ((object)SampleAreaFeature.get_Value(idIndex)).ToString()
таким образом заставляя.ToString() разрешать напрямую, а не через dynamic
,