【发布时间】:2018-09-20 14:02:43
【问题描述】:
我正在使用名为 ArcObjects 和 .NET 4.5 的 API。我遇到了错误
'object' does not contain a definition for 'AddValue'
虽然使用 API 上的对象之一,但我认为这可能是一个比使用此 API 更普遍的 .NET 问题。这是在运行时发生的错误。
在某些背景下,ArcObjects 都是 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。
我可以通过将最后一行更改为以下内容来解决此问题:
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);
这让我想到了手头的问题。为什么这三个 sn-ps 的编译方式不同?
未显式键入的值会产生不同的结果,两者都可以编译,但其中一个无法在运行时绑定到 AddValue 方法。
这里是使用 'var' 关键字时的 IL:
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:
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)
【问题讨论】:
-
这不是那个问题的重复。该问题的结论是编译后隐式和显式类型之间没有有意义的区别。而在这里,当使用 var 而不是显式类型时,我会得到不同的运行时行为。
-
如果
get_Value()返回一个dynamic,或者一个隐藏.ToString()的类型,编译会有所不同。该类型必须隐式转换为定义的字符串,但这是可能的。如果您使用的是 VS,请将鼠标悬停在var上。报告什么类型? -
Microsoft.CSharp.RuntimeBinder的存在为dynamic的可能性提供了支持。 -
@recursive 是正确的,动态是阴影 ToString() 导致 var 是动态的。知道为什么 RuntimeBinder 会失败吗?我通常可以将动态对象传递给强类型函数。我猜这与绑定到底层 COM 对象失败有关。
标签: .net cil arcobjects