
简介这份《GIS程序设计期末复习.docx》面向准备 GIS 程序设计期末考试的高校学生尤其是使用 ArcEngine 进行二次开发、需要系统梳理课本重点的读者。内容按章节归纳 GIS 基本概念、开发与应用模式、AE 组件库与对象模型图、类与对象及接口继承、Workspace 与 Geodatabase 体系、常用控件的分类与特性以及地图组件和数据集之间的接口关系并附有选择、简答、程序设计与面向接口编程等题型的考点提示便于对照课本查漏补缺、按题型组织复习。资源包共 1 个 docx 文件约 983KB单文档结构紧凑适合打印或平板上翻阅。目前已有 1011 人学习可作为考前速览与知识点串联的参考资料。1. 从 COM 到一张地图GIS 程序设计期末复习的知识地图GIS 程序设计的期末复习最容易出现的问题是把 GIS 基础概念、AE 二次开发、COM 接口这三层当成互不相干的内容分开背。这份知识点汇总的价值是把它们串成一条线索底层是类与接口的语法规则中间是控件与地图视图的显示链路上层是数据访问、查询与渲染的业务流程最后都汇到一道程序设计题上。整门课的骨架其实只有一句话用接口拿到对象用对象操作数据用视图把结果画出来。正在系统学这门课、或者考前要快速查漏补缺的人按这条线索复习比按章节顺序硬啃省力得多也更容易在综合题上拿到分。2. 类、接口与对象模型图AE 二次开发的底层语法这一章的知识点是整门课最重要的基础部分也是后面所有接口题的理论来源。很多人背得出「封装、继承、多态」这六个字却说不清 AE 里为什么一个对象能当成好几种类型使用原因就是没把类、接口、组件这三者的关系理顺。2.1 类、对象、接口与 COM 的固定含义类的定义是「定义了对象的特征以及对象外观和行为的模板」对象则是「类的一个实例包括数据以及源代码」。这两句话几乎是每年必考的原话但只背下来不够要能对应到具体场景对象模型图上画的那个方框是类运行时真正在地图上画出东西的那个东西才是对象。类与对象的三大特点是封装性、继承性和多态性其中封装解决的是数据与实现的隐藏继承解决的是复用多态解决的是同一接口在不同对象上表现不同行为。概念定义要点在 AE 里的表现类定义对象特征、外观与行为的模板对象模型图上的方框对象类的一个实例含数据与源代码运行时取到的具体实例接口组件之间通信的基础一组方法与属性的契约方框上伸出的棒棒糖COM组件之间相互接口的规范所有 AE 对象共同遵守的规则COM 的作用要单独记一句它使各种组件和应用软件之间能够用一种统一的标准方式进行交互。这句话看着空其实是解释后面所有接口转换题的前提正因为有统一规范一个对象才能被不同接口反复查询。接口本身通过一种与平台无关的语言 IDL 来描述这是它能跨语言调用的根本原因。一个组件程序里可以包含多个 COM 对象而每个 COM 对象又可以实现多个接口这两句话经常被拆成选择题问「一个 COM 对象能实现几个接口」「一个组件程序包含几个对象」答案都是「多个」。2.2 对象模型图的三种类与两种图标对象模型图的作用有两个显示每一个类的接口、方法和属性显示类与类之间的关系。图上最需要分辨的是三种类的创建方式这是选择题和简答题的共同高频点。类型能否用 new 创建实例从哪里来典型代表抽象类不能创建或实例化只被子类继承接口自身无实例Symbol、Color、Renderer、Element、GeoDataset普通类/可实例化类不能用 new 创建从其他对象获得实例Workspace靠 WorkspaceFactory.OpenFromFile 取得组件类/CoClass可以用 new 创建直接实例化QueryFilter、FeatureLayer、SimpleMarkerSymbolClass 与 CoClass 的主要区别只有一句话CoClass 是带构造函数的 Class因此可以用 new 直接创建对象。这句话能解释上面整张表抽象类没有构造函数所以不能 new普通类虽然有构造函数但这套体系不让你直接调只有 CoClass 才开放 new。符号体系上还有两个图标必须认准哑铃形状的图标表示属性棒棒糖形状的图标表示查找接口。图上看到一个类有多个棒棒糖说明这个对象能扮演多个角色考试里凡问「这个对象支持哪些操作」答案就在这些小图标上。梳理下来会发现抽象类、普通类、组件类这个三分法几乎贯穿了后半本书Symbol 是抽象类所以要 new SimpleMarkerSymbolRenderer 是抽象类所以要 new SimpleRendererGeoDataset 是抽象类所以 FeatureClass 和 FeatureDataset 才是它的实例形态。记住这条主线比孤立背十几个类名要稳。2.3 接口继承、接口转换与面向接口编程接口继承与接口转换是程序设计题里最确定会考的一块。接口继承指的是接口之间也有派生关系例如 IFeatureClass 继承自 IClassIFeatureLayer 继承自 ILayerISpatialFilter 继承自 IQueryFilter。继承意味着子接口自动拥有父接口的全部成员所以一个要素类对象天生就带着 IClass 那套能力。接口转换则是同一个对象在不同接口视角之间切换本质是在问「这个对象支不支持这个契约」。// 同一个图层对象用不同接口视角去操作 ILayer layer map.get_Layer(0); // 所有图层都实现的公共接口 IFeatureLayer featureLayer layer as IFeatureLayer; // 转成要素图层专用接口 if (featureLayer ! null) { IFeatureClass fc featureLayer.FeatureClass; // 数据源挂在要素类上 int count fc.FeatureCount(null); // 参数传 null 表示不过滤统计全部要素 }这段代码的关键不在语法而在两点。第一as转换对应 COM 里的接口查询转换失败返回 null 而不抛异常所以后面必须判空直接用强制转换的话失败会抛异常考试里写代码不判空是要扣分的。第二FeatureCount(null)的参数是一个查询过滤器传 null 表示不加任何属性或空间约束。面向接口编程的意义也在这里调用方只依赖接口不依赖具体类将来把 shapefile 换成别的数据源调用代码几乎不用动。这也是为什么题目反复强调「面向接口编程」它不是一句口号而是能直接减少改代码量的写法。3. 控件与地图视图兄弟控件、Map 双重身份与 IActiveView控件题几乎每年都有一道问法很朴素AE 有哪些控件、各有什么特点、什么是兄弟控件。但真正拉开分差的是后半段Map 和 PageLayout 都实现了 IActiveView为什么还要分两个接口体系图形元素和框架元素又分别归谁管。3.1 五类控件的分工与兄弟控件的绑定分类控件主要职责制图控件MapControl、PageLayoutControl显示地图与版面视图框架控件TOCControl、ToolbarControl图层树管理、命令与工具承载许可控件LicenseControl初始化组件许可符号控件SymbologyControl选择与预览符号三维控件GlobeControl、SceneControl三维场景显示控件有三个特性可以嵌入到已有的应用程序中增加地图功能能对交互事件和自身事件进行响应存在同伴控件。同伴控件这个概念一定要落到用法上它指的是框架控件本身不显示地图必须绑定一个制图控件才能工作。// 框架控件绑定制图控件TOC 显示图层树Toolbar 的缩放漫游作用于地图 axTOCControl1.SetBuddyControl(axMapControl1); axToolbarControl1.SetBuddyControl(axMapControl1);SetBuddyControl的参数是被绑定的容器对象绑定之后 TOCControl 会自动同步 MapControl 里的图层列表ToolbarControl 上的命令才知道该对哪个视图生效。如果不绑定就直接操作典型表现是点了放大按钮地图毫无反应这是新手最常遇到的「翻车」现场排查顺序永远是先看同伴控件绑没绑。3.2 Map 的双重身份与 IMap、IActiveViewMap 组件有双重身份一方面它是地图数据的管理者和容器另一方面它又是地图数据的显示器。这个双重身份解释了为什么 Map 里只有两类数据空间数据和元素。空间数据就是一个个图层元素则是标注、图框之类的图形对象二者在 Map 里并存但地位不同。地图文档接口至少包括一个地图对象并且有且只有一个当前地图这句话是判断题的常客注意「至少一个」和「有且只有一个」分别对应「地图总数」和「当前地图」。IMap 接口管的是数据侧管理 Map 对象中的 Layer 对象以及要素选择集。IActiveView 则是 Map 对象中最主要、最常用的接口之一它定义了 Map 对象的数据显示功能通过它可以在地图上绘制图形、改变视图范围、获取指北针。// 视图接口是显示层的总入口所有看得见的操作都从这里走 IActiveView activeView axMapControl1.ActiveView; IEnvelope extent activeView.Extent; // 当前视图范围缩放定位都靠它 activeView.Refresh(); // 改完渲染或加完元素必须刷新否则界面没变化Extent属性返回当前视图范围做缩放到图层、定位要素这类功能时都是先改 Extent 再 Refresh。Refresh 这一步最容易漏代码逻辑全对但界面纹丝不动八成就是忘了它。3.3 PageLayout、图形元素与地图修饰框架PageLayout 和 Map 都是视图对象都实现了 IActiveView 接口都是图形元素的容器都能存储图形元素也都实现了 IGraphicsContainer。它们的区别在于装什么Map 中只能保存图形元素PageLayout 既能保存图形元素也能保存框架元素。这一条几乎必考答题时把「图形元素」和「框架元素」两个词写清楚就能拿分。IGraphicsContainer 负责管理 Map 和 PageLayout 对象上存储的数据可以添加、删除、更新元素对应 AddElement 和 DeleteElement 两个方法。IElement 是所有图形元素和框架元素的公共接口Element 则是抽象类。这里最容易记错的是接口之间的关系IElement、ILineElement、ITextElement 并不是父子关系而是同一个对象实现的多个接口并且只有 IElement 才带 Geometry 属性。判断某个属性归谁先问这个属性是不是所有元素都有的是就归 IElement。框架元素里最重要的是两个MapFrame 是 Map 的容器用来管理框架中的地图对象接口为 IMapFrameMapSurroundFrame 是地图修饰框架接口为 IMapSurroundFrame。地图修饰对象指图例、比例尺、指北针这些它们的形状会随 Map 的属性大小变化并且不会直接加入页面布局而是加入 MapSurroundFrame 这一特定类型的框架元素。以指北针为例MarkerNorthArrow 是一个组件类继承 NorthArrow 抽象类实现 IMarkerNorthArrow 和 INorthArrow 两个接口前者设置颜色、尺寸等一般属性后者定义一个 MarkerSymbol 用于设置符号外观。地图打印对应 Printer 抽象类同样是不能直接 new 的类型。4. 数据与查询从 WorkspaceFactory 到要素类家族和空间分析这一章是综合题的主要来源也是知识点密度最高的一块。数据访问题基本都遵循同一个流程找到工作空间工厂用它打开工作空间从工作空间里取要素类把要素类绑到要素图层上最后加进地图并刷新。4.1 Geodatabase、Workspace 与工作空间工厂Geodatabase 是地理信息的物理存储方式主要保存在一个数据库管理系统或文件系统中。它的优点和缺点要成对记答简答题时缺一项就丢分。维度内容优点异构数据逻辑统一、面向对象模型设计、内嵌空间规则、空间属性一体化存储、支持网络拓扑缺点不能充分描述约束规则、不涉及时空数据的表达和处理Workspace 是普通类理解它要抓住两个层面物理级别上它就是地理数据库本身逻辑级别上它是包含空间数据集和非空间数据集的数据容器。IWorkspace 接口定义了访问工作空间各种属性方法。工作空间工厂是 Geodatabase 的入口它是一个抽象类派生出很多子类例如 SdeWorkspaceFactory、AccessWorkspaceFactory、ShapefileWorkspaceFactory不同对象需要不同的工作空间工厂才能打开一个工作空间。这句话的潜台词是工厂选错了后面全错而且报错信息往往很难看出是工厂的问题。OpenFromFile 方法用于访问一个磁盘上已有的目录它返回的是 IWorkspace需要再转成具体的工作空间接口才能继续取数据。数据源层还有两个命名空间值得记住DatasourcesGDB 包含为存储在关系数据库中的矢量和栅格数据提供的工作空间和工作工厂DatasourceFile 是基于文件的数据源包含为支持矢量数据格式提供的工作空间和工作空间工厂。Carto 则包含数据显示服务的对象支持各种数据类型的图层与渲染其中就包括 Map 和 PageLayout。4.2 要素类家族FeatureClass、FeatureLayer、Feature 的关系这一组关系是简答题的必考项问法通常是「数量数据集有哪些相关的类以及它们之间的关系」。类型角色定位关键接口说明FeatureClass存储空间数据的对象类IFeatureClass 继承 IClassObjectClass 的扩展本身不能被 newFeatureLayer要素的显示层IFeatureLayer 继承 ILayer通过 FeatureClass 属性绑定数据源Feature单个要素即一条记录IFeature由游标逐个取出FeatureDataset要素数据集IFeatureDataset 继承 IDataset可容纳多个要素类GeoDataset抽象类代表有空间属性的数据集IGeoDataset实例形态含 FeatureDataset、FeatureClass、TIN、RasterDataset非 GeoDataset无空间属性的数据—Table、ObjectClass、RelationshipClass关系链条可以这样记IFeatureLayer 通过 FeatureClass 属性指向真正的数据源要素类通过游标产出一个一个 Feature而 FeatureClass 自己属于 GeoDataset 这个抽象类家族。还有一条容易忽略的差别要素图层可以创建自己的对象要素类不行所以图层是「可创建」的而要素类只能从工作空间里取。ILayer 接口是所有图层类都能实现的公共接口定义了所有图层的公共方法和属性设置数据源时才需要往下降到 IFeatureLayer。4.3 加载 shapefile 的七步流程// 七步加载 shapefile路径 → 工厂 → 工作空间 → 要素类 → 图层 → 数据源 → 上地图 string folderPath D:\gisdata; // 注意是目录不是 .shp 文件的全路径 string fileName roads.shp; IWorkspaceFactory factory new ShapefileWorkspaceFactory(); // 1、2 选定并创建工厂 IWorkspace workspace factory.OpenFromFile(folderPath, 0); // 3 打开工作空间第二参数留 0 IFeatureWorkspace featureWorkspace workspace as IFeatureWorkspace; IFeatureClass featureClass featureWorkspace.OpenFeatureClass(fileName); // 4 取要素类 IFeatureLayer featureLayer new FeatureLayer(); // 5 创建要素图层 featureLayer.FeatureClass featureClass; // 6 绑定数据源 featureLayer.Name featureClass.AliasName; // 图层名TOC 里显示的就是它 axMapControl1.Map.AddLayer(featureLayer); // 7 加入地图 axMapControl1.ActiveView.Refresh(); // 加完不刷新界面不会变参数上要留意三处OpenFromFile 的第一个参数是目录路径而不是文件路径传成 .shp 全名会直接失败第二个参数是预留位填 0 即可OpenFeatureClass 的参数是数据源名称要素类名与图层名是两个概念前者是数据后者是显示。失败时的排查顺序也固定先确认目录有没有写错再确认工厂类型和数据格式是否匹配最后看接口转换有没有拿到 null。这七步在程序设计题里几乎是默写级别的要求顺序不能乱尤其是「先绑数据源再加地图」这一步反过来做虽然有时也能跑但图层会是空的。4.4 属性查询与空间查询过滤器、游标与空间算子查询相关的类和接口可以按「约束条件」和「结果载体」两类来记。对象作用接口QueryFilter通过属性值或属性之间的关系过滤IQueryFilterSpatialFilter通过空间位置加属性约束过滤ISpatialFilter 继承 IQueryFilterQueryDef用表达式直接查表表必须位于同一工作空间IQueryDefCursor指向数据的指针本身不含数据ICursorFeatureCursor指向一个或多个要素的游标IFeatureCursorQueryFilter 有三个必答要点WhereClause 表示过滤条件不同数据源语法不同SubFields 定义用于数据过滤的属性字段列表Cursor 本质上是一个指向数据的指针本身不包含数据内容只是提供了一个链接到 Row 对象或要素对象的桥梁。游标有三种类型查询游标、插入游标、更新游标并且不能直接创建需要相关接口来实现。FeatureCursor 是 Cursor 的子类指向一个或多个要素实现了 IFeatureCursor 接口。// 属性查询建过滤器 → 拿游标 → 逐个取要素 IQueryFilter queryFilter new QueryFilter(); queryFilter.WhereClause POP 10000; // 语法随数据源变字段名要与数据源一致 queryFilter.SubFields NAME,POP; // 只取需要的字段减少无用开销 IFeatureClass fc featureLayer.FeatureClass; IFeatureCursor cursor fc.Search(queryFilter, false); // false 表示不重用游标对象 IFeature feature cursor.NextFeature(); while (feature ! null) { // 在此读取字段值或做统计 feature cursor.NextFeature(); // 游标自己一步步往前走 }空间查询就是在属性过滤的基础上再加空间约束ISpatialFilter 继承自 IQueryFilter同时包含空间查询和属性查询两种约束常用属性是 Geometry 和 SpatialRel前者给定参照几何后者给定空间关系。空间关系运算之上还有三层能力要分清空间拓扑分析用 ITopologicalOperator负责求交、求并、缓冲这类几何运算叠加分析用 IBasicGeoprocessor统计用 IDataStatistics。调用 GP 工具主要应用 GeoProcessor 类使用方式有两种使用 GeoProcessing 组件的方法或使用 Geoprocessor 托管组件的方法。这两条经常被拿来出选择题关键词是「组件方法」与「托管组件方法」的对应。5. 易错点接口继承、要素类与图层、创建方式上的那几个坑5.1 易漏点一能用 new 和不能用 new 混着背易漏点把 Workspace 当成可以直接 new 的类。很多人在写加载数据的代码时第一行就写new Workspace()然后编译不过或者运行时报错。为什么漏抽象类、普通类、组件类这三类的区分只在对象模型图的图标和一句定义里出现过复习时容易被当成名词解释背过去真正写代码时下意识觉得「要用就 new 一个」。怎么补把「能不能 new」当成判断类的第一问形成条件反射。抽象类完全不能实例化只能被继承接口普通类不能用 new必须从别的对象那里拿实例Workspace 就是典型只能通过 WorkspaceFactory.OpenFromFile 取得组件类才能 new。同一套判断也适用于 Symbol、Color、Renderer 这些抽象类写渲染代码时先想清楚该 new 哪个具体子类例如用 SimpleMarkerSymbol 而不是 Symbol。5.2 易漏点二FeatureClass 和 FeatureLayer 谁装数据谁管显示易漏点把要素类当成图层直接往地图上加或者反过来去要素图层上找要素集合。为什么漏这两个词在中文里都叫「要素××」读起来很像同一个东西而且它们经常在同一段代码里前后出现边界就被模糊掉了。怎么补记住一句分工要素类负责存要素图层负责显。数据源属性在 IFeatureLayer 的 FeatureClass 上所以要拿要素必须先从图层下探到要素类再开游标。反过来AddLayer 只接受图层对象不接受要素类。判断某个操作该找谁看它是在问「数据长什么样」还是「数据怎么显示」前者归要素类后者归图层。IFeatureClass 继承自 IClass是 ObjectClass 的扩展这一点也说明它本质上是数据侧的对象类不是显示侧的东西。5.3 易漏点三以为接口之间有继承才能互相转换易漏点看到 IElement 和 ILineElement就默认它们是父子接口进而以为只有 IElement 才有 Geometry 属性这句话是错的。为什么漏平时写代码习惯了「父类有的子类都有」把这套面向对象直觉直接搬到 COM 接口上忽略了「一个对象实现多个接口」这种平行关系。怎么补区分两种情形。一种是真继承例如 IFeatureLayer 继承 ILayer、ISpatialFilter 继承 IQueryFilter、IFeatureDataset 继承 IDataset子接口天然拥有父接口成员另一种是同一对象实现多个平行接口ILineElement、ITextElement 与 IElement 就属于这种它们之间没有父子关系但可以互相转换而公共的 Geometry 属性只挂在 IElement 上。考试里遇到「某属性属于哪个接口」的题先判断它是所有元素共有还是某类元素专有。5.4 易漏点四查询对象和游标用完了不释放也不判空易漏点as转换之后不判空就直接调成员游标遍历完不释放改了渲染不刷新。为什么漏这几步在示例代码里经常被省略看起来不影响主流程复习时也就跟着省了。但考试的程序设计题会按步骤给分缺一步就是缺一分。怎么补把四个动作固化成书写习惯接口转换后判空、游标用完释放、图层加完刷新、渲染对象设完赋值给图层的 Renderer 属性。刷新这一步尤其容易漏因为代码不报错只是界面上什么都没发生属于典型的「看着对但没效果」。属性查询和空间查询的题最后一般都要落到「查出来、选中、渲染」这条链上少任何一环结果都出不来。6. 复习清单考前把这张图完整走一遍复习到这一步剩下的不是再看一遍书而是按依赖顺序把知识过一遍每一层都能自己讲出「为什么是这样」。下面这份清单按从底层到应用的顺序排每一行都对应一个能自问自答的问题。顺序复习内容自检问题1类、对象、接口、COM一个 COM 对象能实现几个接口接口靠什么语言描述2三类类与两种图标抽象类和普通类的实例分别从哪来哑铃和棒棒糖各表示什么3控件与兄弟控件五类控件各举一例同伴控件不绑会怎样4Map 双重身份与接口IMap 和 IActiveView 各管什么Extent 改完为什么要 Refresh5元素体系Map 和 PageLayout 各能装什么元素MapSurround 为什么不直接进版面6数据访问七步每一步用哪个接口哪一步最容易传错参数7要素类家族FeatureClass、FeatureLayer、Feature 三者的关系链怎么画8查询与分析QueryFilter 三个要点是什么ISpatialFilter 多了什么清单过完之后建议做一件很具体的事拿出一张白纸从new ShapefileWorkspaceFactory()开始一路写到ActiveView.Refresh()中间每一行都标注用的是哪个接口、为什么必须转成这个接口。能把这条链默写完整数据访问和查询类的题基本不会失分。然后再从new SimpleMarkerSymbol()写一条渲染链把符号、渲染器、图层三者怎么挂起来说清楚程序设计题的骨架就有了。最后是接口题的自查方法任意挑三个接口问自己它们之间是真继承还是平行实现如果是继承父接口的哪些成员会被子接口带走如果是平行公共属性归谁。这个方法比反复看对象模型图有效因为它是主动回忆而不是被动扫图。我自己的血泪经验是第一次做综合题时把OpenFromFile的参数传成了 .shp 文件的完整路径调试了半天以为是工厂类型选错最后发现只是路径层级写错了一级。从那以后我每次写数据访问都强制先把「目录、工厂、工作空间、要素类、图层、数据源、刷新」这七步在心里默念一遍再动手敲代码返工次数明显少了。希望帮到你。本文还有配套的精品资源点击获取