ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

GIS程序设计期末复习:AE二次开发对象模型与查询考点

GIS程序设计期末复习:AE二次开发对象模型与查询考点

简介:这份 GIS 程序设计期末复习文档面向准备期末考试的高校学生与 GIS 开发入门者,围绕 ArcEngine 二次开发梳理课本核心考点,可用于考前查漏补缺与快速回顾。压缩包仅含 1 个 docx 文件,约 983KB,篇幅集中、便于打印和批注,内容覆盖 GIS 概念与应用/开发模式、COM 组件、类与对象、接口继承、Workspace 与 Geodatabase、常用 AE 控件、地图组件及空间数据加载等模块。文档还按选择、简答、程序设计和基于 AE 的程序流程归纳题型,点到接口转换、对象模型图、图层渲染、属性查询与空间查询等高频内容,并附矢量数据集相关类关系等复习线索。已有 1011 人学习,适合需要系统整理知识框架、对照题目复盘重点的读者使用。

1. 期末卷子的分是怎么丢的:先看考点分布再决定背什么

「GIS程序设计期末复习」这份知识点汇总覆盖面看着吓人,其实分值流向很清楚:选择填空吃概念,简答吃对象模型图,程序设计题吃 AE 二次开发里的四条链路——数据加载、图层渲染、属性查询、空间查询。AE二次开发最玄学的地方不是算法,而是「这个类到底能不能 new」:Workspace、FeatureClass、Element 这些看着就该实例化的东西,偏偏要绕一层工厂或接口去取。期末考试每年翻车的都在这几个点上。知识点汇总里那几张对象模型图和接口清单,就是给你在考场上默写用的。适合已经把教材过过一遍、能看懂代码但写不出接口名的人,照着下面几章顺一遍,简答和程序设计题基本能拿到该拿的分。

2. 概念与对象模型:选择题和简答的送分区,先把三种类分清

2.1 GIS 应用模式与开发模式,这四个词别混着答

这一节的知识点全是名词,但选择题和简答题的坑恰恰在名词之间的边界上。应用模式说的是系统怎么部署:单机模式、局域网模式、广域网模式,三个词对应的是用户和数据放在哪。开发模式说的是系统怎么造出来:独立开发模式、单纯二次开发、集成二次开发,其中集成二次开发又分 OLE/DDE 和组件式两条路。考场上最常见的失分是把「应用模式」和「开发模式」的答案写串,比如问开发模式却答了单机、局域网、广域网,字都写了,分没了。

组件式开发之所以成为主流,原因要能一句话说清:组件之间的接口用与平台无关的 IDL 描述,所以组件可以跨语言、跨环境拼装。COM 则是组件之间相互接口的规范,作用是让各种组件和应用软件之间用统一标准的方式交互。这两句几乎能套用所有「为什么用组件」「COM 是什么」的问法,建议原样背下来,答题时先给定义再展开。

GIS 组件本身分三类:基础组件、高级通用软件、行业性组件。基础组件提供最底层的通用能力,高级通用软件在基础组件之上封出更贴近业务的模块,行业性组件则直接面向某个应用领域。这个分类常以选择题出现,考的是「哪一项不属于」这类判断题,记顺序比记定义更管用。

应用型 GIS 设计的内容与过程是五步:系统总体设计、数据库详细设计、系统功能设计、应用模型和方法设计、输入输出设计。简答题如果问「设计过程包括哪些环节」,按这五步写,顺序不要乱,因为顺序本身就体现了从整体到细节、从数据到功能的推演逻辑。

提示:名词题不要追求写得多,追求写对层次。先答「分几类」,再答「分别是什么」,最后挑一个展开一句,这是最稳的三段式。

真题演练:简述 GIS 的开发模式,并说明集成二次开发为什么常用。

答题思路:第一段列三种模式并各给一句解释,独立开发是从底层自己写、工作量大;单纯二次开发是在现成软件上做扩展、受宿主限制;集成二次开发是把组件嵌进自己的程序里、兼顾灵活性和开发效率。第二段直接落到组件式的两个优势:接口由 IDL 描述所以与平台无关,组件可复用所以不用重造轮子。第三段补一句 COM 的作用收尾。三段写完,这题的分就稳了。

2.2 类、对象与接口:封装、继承、多态的标准答法

类定义了对象的特征以及对象外观和行为的模板;对象是类的一个实例,既包含数据也包含操作这些数据的代码。这两句是简答题的地基,写不准后面全歪。类与对象的三特性是封装性、继承性、多态性,答题时不要只写三个词,每个词后面跟半句解释:封装把数据和操作包在一起并隐藏实现细节,继承让子类复用父类的接口和行为,多态让同一个接口在不同对象上有不同表现。

接口是组件之间通信的基础。这句要配合下面的数量关系一起记:一个组件程序包括多个 COM 对象,每个 COM 对象又可以实现多个接口。考试喜欢在这里出选择题,把「一个组件只有一个对象」「一个对象只能实现一个接口」写成干扰项。

注意:面试或答辩时被追问「接口和抽象类的区别」,答案不要往语法上靠,往「接口定义契约、抽象类提供部分实现」上说,再补一句本课程里的实际用法——用接口声明变量、用组件类实例化,这样答既对题又落到 AE 上。

2.3 对象模型图三大类:抽象类、普通类、组件类,判断能不能 new 是核心

对象模型图是这门课简答题的高频区,图上每一个类都要能归到三类里,归类错了后面全错。三类特点如下:

类型能否用 new 创建实例从哪来典型判断依据
抽象类不能创建,也不能实例化由子类实现后间接使用图上是空心或带抽象标记,子类继承它的接口
普通类(可实例化类)不能用 new 创建从其他对象上取得实例常见于 Workspace、各类数据集
组件类(可创建类)可以用 new 创建自己实例化图上有构造函数标记,CoClass 就属于这类

这张表要能默写。考场上最常见的错是看到「可实例化」四个字就写 new,其实「可实例化」说的是它有实例,只是实例不归你创建,得从工厂、从别的对象上取。Class 和 CoClass 的主要区别就是 CoClass 是带构造函数的 Class,所以它能用 new 直接创建对象;普通 Class 没有这一步,只能等别人给。

对象模型图上还有两个图标约定要认清:哑铃形状的图标表示属性,棒棒糖形状的图标表示接口。这类题通常给一小段模型图描述,让你判断某个类实现了哪些接口、能不能直接 new、某个属性属于哪个接口,答的时候先定位图标再下结论,别凭类名猜。

真题演练:说明抽象类、普通类、组件类的区别,并指出对象模型图中如何判断一个类能否用 new 创建。

答题思路:先用一句话定性——三者的区别不在功能,而在「谁来创建实例」。再逐个展开:抽象类不能创建也不能实例化,子类继承它的接口;普通类有实例但不能用 new,要从其他对象获得;组件类可以用 new 直接实例化。最后落到识图方法:看有没有构造函数标记,看它是不是 CoClass,看类名在图上是否被别的类继承。这样答,判卷人一眼就能看到你懂的是判断逻辑而不是死记。

3. 控件与地图组件:五类控件、兄弟绑定,以及 Map 的两副面孔

3.1 五类控件清单与「兄弟控件」的答题模板

AE 的控件按用途分五类,这个清单必须张口就来:制图控件是 MapControl 和 PageLayoutControl;框架控件是 TOCControl 和 ToolbarControl;许可控件是 LicenseControl;符号控件是 SymbologyControl;三维控件是 GlobeControl 和 SceneControl。选择题常在这里挖坑,把 SymbologyControl 混进制图控件里,或者把 SceneControl 说成二维控件,记的时候按「制图—框架—许可—符号—三维」的顺序背,五组一起出来不容易漏。

控件的特性有三条:可嵌入到已有的应用程序中增加地图功能;能对交互事件和自身事件进行响应;存在同伴控件。第三条就是「兄弟控件」考点的来源。所谓兄弟控件,指的是 TOCControl、ToolbarControl 这类自己不画地图、必须绑定到某个 MapControl 或 PageLayoutControl 上才能工作的控件。它们和制图控件之间是伙伴关系,绑定的意义在于共享同一份地图数据:TOCControl 显示图层的目录树,ToolbarControl 提供放大、缩小、 pan 这些命令,两者操作的对象必须是 MapControl 里那张地图,否则点了没反应。

答题时最容易被扣分的地方是只说「兄弟控件要绑定」,不说绑定什么。完整说法是:TOCControl 和 ToolbarControl 通过 SetBuddyControl 方法与制图控件建立伙伴关系,共享同一个地图或页面布局对象,从而实现图层目录与地图视图、工具命令与地图视图的联动。这句话里「共享同一个地图对象」是得分点。

提示:控件类简答题按「有哪些—各自干什么—彼此怎么配合」三层写,比罗列名字多拿一半分。

3.2 Map 的双重身份:IMap 管数据,IActiveView 管显示

地图组件是双重身份:一方面它是地图数据的管理者和容器,另一方面它又是地图数据的显示器。这句话几乎每年都考,答不出「双重」两个字,后面写再多也是白搭。

地图文档接口至少包括一个地图对象,有且只有一个当前地图。IMap 接口管的是 Map 对象里的 Layer 对象和要素选择集,也就是「地图里有哪些图层、选中了哪些要素」。IActiveView 是 Map 对象最主要、最常用的接口之一,它定义的是数据显示功能:可以在地图上绘制图形、改变视图范围、拿到指北针这类修饰对象,它的 Extent 属性返回地图视图的当前范围。

两个接口的分工要能用一句话概括:IMap 管内容,IActiveView 管呈现。代码里也常这么写:先拿 IMap 加图层,再 as 成 IActiveView 调 Refresh。这个套路在第 4 章的加载流程里会反复出现。

3.3 元素体系:IElement 不是 ILineElement 的父接口

PageLayout 和 Map 都是视图对象,都实现了 IActiveView 接口,都是图形元素的容器,都实现了 IGraphicsContainer。差别在于装什么:Map 中只能保存图形元素,PageLayout 既能保存图形元素,也能保存框架元素。这个差别是选择题的高频点,记法是「页面布局比地图多装一类东西」。

IGraphicsContainer 管的是 Map 和 PageLayout 上存的数据,用这个接口可以添加、删除、更新元素,对应的方法是 AddElement 和 DeleteElement。IElement 是所有图形元素和框架元素的接口,Element 是抽象类。

这里有一个年年有人踩的坑:IElement、ILineElement、ITextElement 并不是父子关系,三者之间只有 IElement 有 Geometry 属性。也就是说,你不能因为一个元素是线元素,就认为它「继承自 IElement」,它们是不同接口,只是同一个对象可能同时实现多个接口。答这类判断题,先问「谁有 Geometry」,再问「谁是谁的父接口」。

框架元素这边要分清三样东西。MapFrame 是地图框架,是 Map 的容器,用来管理框架中的地图对象,接口是 IMapFrame。MapSurroundFrame 是地图修饰框架,接口是 IMapSurroundFrame。MapSurrounds 指图例、比例尺、指北针这类对象,它们的形状会随 Map 的属性大小变化而变化,而且不会直接加入到页面布局里,而是加到某一特定类型的框架元素中,这个框架元素就是 MapSurroundFrame。

指北针常被单独拿出来考。MarkerNorthArrow 是一个组件类,继承 NorthArrow 抽象类,用于指示地图方位,它实现了两个接口:IMarkerNorthArrow 用于设置指北针对象的一般属性,比如颜色、尺寸;INorthArrow 定义一个 MarkerSymbol,用于设置指北针的符号。一个对象两个接口、各管一摊,这种设计在 AE 里很常见,答题时把「接口分工」点出来就是加分项。地图打印对应的是 Printer 抽象类,记住它是抽象类、不能直接 new 就够了。

3.4 简答演练:控件特性与元素添加流程

真题:简述 AE 控件的特性,并说明向 Map 中添加一个图形元素的步骤。

答题思路分两段。第一段写三条特性:可嵌入已有程序增加地图功能、能响应交互事件和自身事件、存在同伴控件,每条后面补半句解释,比如同伴控件那条要点出 TOCControl 与 MapControl 的绑定关系。第二段写步骤,按「取容器—造元素—给几何—加进去—刷新」五步走:先用 IGraphicsContainer 拿到地图的容器接口,再 new 一个具体的元素类并 as 成 IElement,接着给它的 Geometry 赋一个几何对象,然后 AddElement 添加,最后用 IActiveView 的 Refresh 刷新视图。

代码骨架长这样,考试时按这个结构写,接口名写错一两个也还能拿到步骤分:

// 1) 从地图上取图形容器接口(Map 和 PageLayout 都实现了它) IGraphicsContainer pContainer = pMap as IGraphicsContainer; // 2) 造一个具体元素,并用接口接收(面向接口编程) IElement pElement = new TextElementClass(); // 3) 给元素指定几何位置,文本元素用 IPoint 定位 IPoint pPoint = new PointClass(); pPoint.PutCoords(100, 100); pElement.Geometry = pPoint; // 4) 加进容器 pContainer.AddElement(pElement, 0); // 5) 刷新视图,否则界面上看不到 IActiveView pActiveView = pMap as IActiveView; pActiveView.Refresh();

这段代码里最关键的两行是第二行和第五行。第二行用 IElement 声明、用 TextElementClass 实例化,是面向接口编程的最小示例;第五行刷新是血泪经验,不写 Refresh,元素其实已经加进去了,但界面一片空白,考生会以为自己加错了,回头改代码越改越乱。参数上 AddElement 的第二个参数是图层索引,0 表示放在最上面,考试写 0 最安全。

4. 数据访问链:工作空间工厂、要素类与图层,加上渲染和两类查询

4.1 工作空间工厂:Workspace 为什么不能 new

Geodatabase 是地理信息的物理存储方式,主要保存在一个数据库管理系统或文件系统中。它的优点有五条:异构数据逻辑统一、面向对象模型设计、内嵌空间规则、空间属性一体化存储、支持网络拓扑。缺点两条:不能充分描述约束规则、不涉及时空数据的表达和处理。这七条建议原样背,简答题几乎逐字给分。

工作空间是数据容器,物理级别上它就是地理数据库本身,逻辑级别上它是包含空间数据集和非空间数据集的数据容器。IWorkspace 定义了访问工作空间各种属性的方法,IFeatureClass 管理要素数据集。

工作空间工厂是 Geodatabase 的入口,它是一个抽象类,派生出很多子类,比如 SdeWorkspaceFactory、AccessWorkspaceFactory、ShapefileWorkspaceFactory。不同的数据源要用不同的工作空间工厂来打开对应的工作空间,这句话是简答题的得分句。Workspace 本身是一个可实例化的类,但不能用 new 创建,要用 IWorkspaceFactory 的 OpenFromFile 方法打开一个磁盘上的现有目录来取得。这就是上一章说的「可实例化但不能 new」的典型例子,也是全卷最容易被抓的错。

DatasourceGDB 包含了为存储在关系数据库中的矢量和栅格数据提供的工作空间和工作工厂;DatasourceFile 是基于文件的数据源,包含了为支持矢量数据格式提供的工作空间和工作空间工厂。这两个名字长得像,考试时常被拿来出「哪个对应文件、哪个对应数据库」的配对题。

4.2 FeatureClass、FeatureLayer、Feature 的三层关系,以及 GeoDataset 的分界

这三个词是整门课最容易被写混的一组,先把定义钉死:FeatureClass 是要素类,用来存储空间数据的对象类,是 ObjectClass 的扩展,它继承自 IClass 接口;FeatureLayer 是要素图层,负责显示,通过 IFeatureLayer 设置数据源,也就是指定它显示哪个 FeatureClass;Feature 是单个要素,是 FeatureClass 里的一条记录。

三者关系一句话概括:FeatureClass 存数据,FeatureLayer 显示数据,Feature 是数据里的一行。判断「谁能创建对象」的时候要注意:FeatureLayer 可以创建自己的对象,FeatureClass 不行。这个细节经常出判断题。

ILayer 接口是所有图层类都要实现的接口,定义了所有图层的公共方法和属性;IFeatureLayer 继承自 ILayer,在此之上增加了数据源设置等要素图层特有的能力。接口继承关系是简答题的常见问法,答的时候画不出图就用文字写「IFeatureLayer 继承 ILayer,因此 ILayer 的方法在要素图层上同样可用」。

GeoDataset 是一个抽象类,代表拥有空间属性的数据集,它的例子包括 FeatureDataset、FeatureClass、TIN 和 RasterDataset。非 GeoDataset 包括 Table、ObjectClass 和 RelationshipClass。IFeatureDataset 是要素数据集,继承自 IDataset。这条分界线要记牢:带空间属性的往 GeoDataset 归,纯表格和关系类的往非 GeoDataset 归。选择题会让你从五个名字里挑出一个不属于 GeoDataset 的,通常就是 Table 或 RelationshipClass。

4.3 加载 ShapeFile 的七步与代码逐行讲

教材给的加载流程是七步:获取文件路径和文件名称;创建地理空间工厂;实例化工作空间;获取 FeatureClass;创建要素图层 FeatureLayer;为要素图层定义数据集;添加至地图。这七步的顺序不能乱,因为后一步依赖前一步的产出。

// 1) 取文件所在目录和文件名,Shapefile 工厂认目录不认文件 string filePath = @"D:\data\roads.shp"; string directory = System.IO.Path.GetDirectoryName(filePath); string fileName = System.IO.Path.GetFileName(filePath); // 2) 按数据源类型选工厂,Shapefile 对应 ShapefileWorkspaceFactoryClass IWorkspaceFactory pFactory = new ShapefileWorkspaceFactoryClass(); // 3) 用工厂打开工作空间,第二个参数是窗口句柄占位,传 0 即可 IWorkspace pWorkspace = pFactory.OpenFromFile(directory, 0); // 4) 转成要素工作空间接口,再按名字取要素类 IFeatureWorkspace pFeatureWorkspace = pWorkspace as IFeatureWorkspace; IFeatureClass pFeatureClass = pFeatureWorkspace.OpenFeatureClass(fileName); // 5) 新建要素图层,并把要素类指定为它的数据源 IFeatureLayer pFeatureLayer = new FeatureLayerClass(); pFeatureLayer.FeatureClass = pFeatureClass; pFeatureLayer.Name = pFeatureClass.AliasName; // 6) 加进地图,IMap 负责管理图层集合 IMap pMap = axMapControl1.Map; pMap.AddLayer(pFeatureLayer); // 7) 刷新视图,IActiveView 负责显示 IActiveView pActiveView = pMap as IActiveView; pActiveView.Refresh();

逐行看几个参数。第二步选工厂是这题的隐性考点:换成 SdeWorkspaceFactory 就打不开本地 shp,工厂和数据源必须配对。第三步 OpenFromFile 的第一个参数是目录不是文件路径,传成 shp 全路径是最常见的翻车方式,因为方法名里没有 directory 字样,很多人想当然。第二个参数是宿主窗口句柄,考试写 0 就行。第四步要先 as 成 IFeatureWorkspace,因为 IWorkspace 上没有 OpenFeatureClass 方法,这一步是接口转换的实战演示。第五步给 FeatureClass 赋值就是「为要素图层定义数据集」,答题时这两句要对应上,别只写代码不说概念。第七步不刷新等于没加,前面说过,不再重复。

注意:如果题目要求加载的是 Personal GDB 里的要素类,工厂换成 AccessWorkspaceFactory,OpenFromFile 传的是 mdb 文件路径而不是目录,其余步骤完全一样。答题时把「工厂换、路径类型换、后面不变」这三点写出来,比整段重写更显功力。

4.4 符号化与渲染:Color、Symbol、Renderer 三个抽象类

符号化这块先记几何体系:IGeometry 是几何图形的基础接口;IPoint 继承自 IGeometry;IEnvelope 是矩形,也继承自 IGeometry;IPolygon 是多边形;IPolyline 是线。容限反映坐标数据的精度,也就是坐标值之间的最小距离,常用在关系与拓扑运算里;ISpatialReference 管空间参考。单个的 Segment 组成 Path,Ring 是闭合的 Path,这几个词常在填空里出现。

符号化体系里有三个抽象类必须记住:Color、Symbol、Renderer。它们都是抽象类,不能直接 new,要 new 它们的子类,比如 SimpleMarkerSymbol、SimpleLineSymbol、SimpleFillSymbol,颜色用 RgbColor 之类。判断「下面哪个是抽象类」时,Color、Symbol、Renderer 三个一出现基本就是答案。

// 取图层的渲染器:IGeoFeatureLayer 才有 Renderer 属性 IFeatureLayer pFLayer = pLayer as IFeatureLayer; IGeoFeatureLayer pGeoLayer = pFLayer as IGeoFeatureLayer; ISimpleRenderer pRenderer = pGeoLayer.Renderer as ISimpleRenderer; // 造符号并设颜色,点要素用 SimpleMarkerSymbol ISimpleMarkerSymbol pMarker = new SimpleMarkerSymbolClass(); pMarker.Color = GetRgb(255, 0, 0); pMarker.Size = 8; // 把符号塞回渲染器,再刷新 pRenderer.Symbol = pMarker as ISymbol; (pMap as IActiveView).Refresh();

这段的关键在第一个 as:Renderer 属性不在 IFeatureLayer 上,而在 IGeoFeatureLayer 上,直接对 IFeatureLayer 取 Renderer 编译都过不去。第二个关键点是符号类型要和几何类型匹配,点用 Marker、线用 Line、面用 Fill,类型写错运行时不报错但图上什么都不显示,这种静默失败最难查。GetRgb 是教材里给颜色赋值的写法,考试照写即可。

4.5 属性查询三件套:QueryFilter、Cursor、FeatureCursor

属性查询相关的类和接口要成对记:类是 QueryFilter、QueryDef、Cursor、FeatureCursor;接口是 IQueryFilter、IQueryDef、ICursor、IFeatureCursor、IFeatureSelection。

QueryFilter 用属性值或属性之间的关系过滤数据,核心是 WhereClause,不同数据源语法不同,写的时候要说明「语法随数据源变化」;SubFields 属性定义用于过滤的属性字段列表,只取需要的字段能少读一堆数据。SpatialFilter 则是用空间位置加属性约束来过滤,它继承自 IQueryFilter,所以属性和空间两条约束可以同时挂上去。

Cursor 对象本质上是一个指向数据的指针,本身不包含数据内容,只是提供一个链接到 Row 对象或要素对象的桥梁。游标有三种:查询游标、插入游标、更新游标。它不能直接创建,要用相关接口取。FeatureCursor 是 Cursor 的子类,指向一个或多个要素,实现了 IFeatureCursor 接口。

// 1) 造过滤器,条件写在 WhereClause 里 IQueryFilter pFilter = new QueryFilterClass(); pFilter.WhereClause = "POP > 100000"; pFilter.SubFields = "NAME,POP"; // 2) 用要素类的 Search 方法拿游标,第二个参数 false 表示不重用游标 IFeatureCursor pCursor = pFeatureClass.Search(pFilter, false); // 3) 循环取要素,一次一条,取完指针自动后移 IFeature pFeature = pCursor.NextFeature(); while (pFeature != null) { // 在这里读字段、做统计、加进选择集 pFeature = pCursor.NextFeature(); }

逻辑说明:游标是「流式」的,不是一次性把结果搬到内存里,所以必须靠 NextFeature 一步步走,走到 null 结束。参数上 Search 的第二个参数 recycled 传 false,表示每次返回新的要素对象;传 true 性能好但对象会被复用,循环里如果要把要素存起来备用就会出问题,考试里写 false 最稳。用完之后要释放游标,否则数据源被占住,后续操作可能失败。QueryDef 的特点是其中的表必须存放在一个工作空间内,它不是一个组件类,这点常出判断题。

4.6 空间查询、拓扑与叠加:ISpatialFilter、ITopologicalOperator、IBasicGeoprocessor

空间查询的入口是 ISpatialFilter,它继承自 IQueryFilter,同时包含空间和属性两种查询约束。用它要设三个东西:Geometry 指定查询用的几何,GeometryField 指定被查图层的几何字段名,SpatialRel 指定空间关系,比如相交、包含、相离。

// 空间过滤器:几何 + 关系 + 可选属性条件 ISpatialFilter pSpatialFilter = new SpatialFilterClass(); pSpatialFilter.Geometry = pPolygon; // 查询用的面 pSpatialFilter.GeometryField = pFeatureClass.ShapeFieldName; pSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects; pSpatialFilter.WhereClause = "AREA > 500"; // 空间与属性可叠加 IFeatureCursor pCursor = pFeatureClass.Search(pSpatialFilter, false);

这段最容易漏的是 GeometryField,不设它,接口不知道拿哪个字段去比,查询结果要么为空要么报错。SpatialRel 是枚举,答题时写清「相交、包含这类关系由该属性指定」即可,具体枚举名记不住可以写中文含义加英文关键字段。

空间拓扑分析用 ITopologicalOperator,做缓冲区、求交、求并这类几何运算;叠加分析用 IBasicGeoprocessor;统计用 IDataStatistics。调用 GP 工具主要用 Geoprocessor 类,使用方式有两种:直接用 GeoProcessing 组件的方法,或用 Geoprocessor 托管组件的方法。这两种方式的区别是前者更底层、后者封装更全,简答题点到「一种偏组件调用、一种偏托管封装」就够。

4.7 面向接口编程与接口转换:程序设计必考题的代码骨架

面向接口编程是这份资料里明确标注「肯定考」的点,答题套路固定:声明变量用接口,实例化用组件类,需要别的接口能力时用 as 转换并判空。

// 声明用接口:调用方只依赖 ILayer,不关心具体是哪个图层类 ILayer pLayer = new FeatureLayerClass(); // 需要要素图层的能力时做接口转换,转换失败返回 null,所以要判空 IFeatureLayer pFeatureLayer = pLayer as IFeatureLayer; if (pFeatureLayer != null) { pFeatureLayer.FeatureClass = pFeatureClass; } // 接口继承:IFeatureLayer 继承 ILayer,所以 ILayer 的成员在这里照样能用 string layerName = pFeatureLayer.Name;

三行注释对应三个考点:第一行是面向接口编程,第二行是接口转换,第三行是接口继承。答题时把这三层各写一句解释,比闷头写一大段代码更容易拿分。接口转换要强调两点:用 as 不用强制括号强转,因为 as 失败返回 null 可以判空,强转失败直接抛异常;转换前先想清楚目标接口的方法到底在哪个接口上,比如 Renderer 在 IGeoFeatureLayer 上、OpenFeatureClass 在 IFeatureWorkspace 上,这不是靠背,是靠平时把接口表看熟。

5. 易错点:五个年年有人翻车的失分点

5.1 概念判断上最容易错的三个点

第一个,把 Workspace 用 new 创建。错在哪:写成IWorkspace pWorkspace = new WorkspaceClass();。为什么错:Workspace 是可实例化的类,但不能用 new 创建,实例要从工作空间工厂来。怎么答对:写成pWorkspaceFactory.OpenFromFile(directory, 0),并在答题时补一句「不同数据源对应不同的工作空间工厂子类」,把工厂与数据源的配对关系一并写出来。

第二个,把普通类当成组件类,随手 new。错在哪:看到类名就 new,比如对数据集类、对抽象类直接实例化。为什么错:抽象类不能创建也不能实例化,普通类有实例但不能用 new,只有组件类才能 new。怎么答对:判断前先看三件事——图上有无构造函数标记、是不是 CoClass、类名是否被别的类继承。答题时把判断依据写出来,即使结论写错也能拿过程分。

第三个,把 IElement 和 ILineElement、ITextElement 当成父子关系。错在哪:答「ILineElement 继承自 IElement,所以有 Geometry 属性」。为什么错:它们不是父子关系,只有 IElement 有 Geometry 属性。怎么答对:先答「三者是不同接口,同一个对象可同时实现多个」,再答「Geometry 属性挂在 IElement 上」,两句话就把这题封死。

5.2 代码题上最容易错的两个点

第四个,把 Cursor 当成数据容器。错在哪:拿到游标后不调 NextFeature,或者只用一次就以为拿到了全部结果;也有人把游标存进集合反复用。为什么错:Cursor 本质是指针,本身不含数据内容,只是链接到 Row 或要素对象的桥梁,取一条指针就动一次。怎么答对:写标准的 while 循环,循环体里pFeature = pCursor.NextFeature();,循环外用 ReleaseComObject 释放;答题时补一句「游标不能直接创建,要用 Search 这类方法取」,把概念分也拿到。

第五个,FeatureClass 和 FeatureLayer 搞反。错在哪:把数据源设成图层,或者对 FeatureClass 调显示相关的方法。为什么错:FeatureClass 负责存储空间数据,FeatureLayer 负责显示,FeatureLayer 的数据源才指向 FeatureClass,而且 FeatureLayer 能创建自己的对象,FeatureClass 不行。怎么答对:加载题里严格按「取 FeatureClass → 建 FeatureLayer → 把 FeatureClass 赋给 FeatureLayer.FeatureClass → 加进 Map」的顺序写,每一步都点明谁是谁的数据源。这个顺序本身就是答案。

6. 答题技巧:从题干关键词到接口名,五步走完一道程序设计题

程序设计题看着自由,其实题干里的每个条件都对应一个接口,读题时把它们圈出来,代码就有骨架了。我的做法是五步:读题拆条件、按条件选接口、写声明与实例化、补关键属性赋值、收尾刷新与释放。

拆条件这一步最值钱。题干说「把某个目录下的矢量数据加载到地图上」,条件就是路径、数据源类型、地图对象三个;说「按属性条件查出来并高亮」,条件是过滤字段、游标、选择集;说「按一个面范围查」,条件里必然出现几何对象和空间关系。把条件列成一行行短句,再逐行找接口,比通读一遍直接下笔稳得多。

下面这张对照表建议考前默一遍,题干关键词和接口基本是一一对应的:

题干关键词首选接口或类常见配套动作
打开数据、加载图层IWorkspaceFactory、IFeatureWorkspace、IFeatureLayer工厂按数据源类型选,最后 AddLayer
显示、刷新、范围IActiveViewRefresh,取 Extent
符号、颜色、样式ISimpleRenderer、ISimpleMarkerSymbol符号类型要与几何类型匹配
属性条件查询IQueryFilter、IFeatureCursor设 WhereClause 与 SubFields
按范围查询ISpatialFilter设 Geometry、GeometryField、SpatialRel
缓冲、求交ITopologicalOperator几何运算后再套查询
统计IDataStatistics配合游标取字段值

写代码时坚持三条硬规矩。第一,声明用接口、实例化用组件类,任何一行都别用具体类做变量类型,这是面向接口编程的判分点。第二,凡是 as 转换后面必须跟判空,判空本身就是得分点。第三,结尾必须有刷新或释放,加载完 Refresh,查完释放游标,这两句是很多人漏掉的收尾分。

提示:实在想不起某个接口名,就把「谁负责什么」写清楚,比如「用负责显示的那个接口刷新视图」,判卷人看到职责划分正确,通常会给步骤分;空着不写才是零分。

从那以后我每次做这类题,都强制走一遍「拆条件—对接口—写骨架—补属性—收尾」这五步,哪怕时间紧也至少把前两步写在草稿上,因为凭感觉直接写代码,十有八九会在某个 as 上卡住,然后整段推倒重来。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进