> ## Content Index
> Fetch the complete content index at: https://blog.anthea.day/llms.txt
> Use this file to discover other available public pages before exploring further.

# NetTopologySuite 處理 GIS (2)：WriteAllFeatures 型別轉換錯誤 Exception
- URL: https://blog.anthea.day/series-net-topology-suite-2/
- Published: 2022-08-26T15:12:45.000Z
- Updated: 2026-10-21T04:08:30.000Z
- Author: Anthea / 芫荽
- Tags: #Migrated-1792241843742, #Import 2026-10-17 12:57, Coding, .NET, NetTopologySuite 處理 GIS

在上一篇文章中，我們順利的使用 `NetTopologySuite.IO.Esri` 來讀取 Shapefile 檔案中的內容，可是在寫出時遇到了一點問題：

![](https://cdn-images-1.medium.com/max/800/1*1bPLF02NQKPToKsUIlomKg.png)

執行後在 WriteAllFeatures 中遇到的 Exception

因此，這篇會探討的主題就是：

1. 為甚麼會發生這個 Exception
2. 如何解決

---

### 這個 Exception 哪裡來

一開始看到錯誤原因的時候真的覺得很茫然 😵 我很確定我的 WKT 是 Polygon 沒有錯，為甚麼 Exception 會告訴我我想把 Polygon 轉換成 Multi Polygon 呢 💫

於是開啟 debbug mode，順著程式碼一行一行往下找，終於在 `Shapefile.cs` 中找到一點線索。在最後要使用 Writer 寫入的時候，他所建立的 Writer 泛型所吃的類別竟然只有 Multi Polygon 的選項 😨

![](https://cdn-images-1.medium.com/max/800/1*F5Z37GLhm55RxMcg7vBw0w.png)

如果是 Polygon 的話會使用 ShapefilePolygonWriter，可以看到帶入的類別是 MultiPolygon

也就是說，Writer 以 Multi Polygon 建立，但我的 Geometry 型別是 Polygon，所以在使用 Writer 前他會一直想把我的型別轉換成 Multi Polygon ，才會一直噴出型別轉換的 Exception。但我仔細看了原始碼，居然只有針對 MultiPolygon 去進行寫入的方法，而且是把所有 Polygon 相關的類別：Polygon、PolygonM、PolygonZ、PolygonZM 都讓 Multi Polygon Writer 去接，好神祕的操作 😵

---

### 把 `ShapefilePolygonWriter` 獨立出來

查到原因之後我最直覺的想法就是把 Polygon Writer 的部分獨立出來，要修改的部分包含四個：`ShapeType`、`Shapefile`、`ShapefileWriter` 和 `ShpWriter`。

#### `ShapeType.cs`

在這邊新增一個判斷，讓 `IsPolygon` 只允許 Polygon 通過，其餘的類別都屬於 MultiPolygon。

```C#
/// <summary>
/// Indicates if shape associated with this type is a Polygon.
/// </summary>
public static bool IsPolygon(this ShapeType type)
{
    // 修改成只符合 Polygon
    return type == ShapeType.Polygon;
}

/// <summary>
/// Indicates if shape associated with this type is a Multi Polygon.
/// </summary>
public static bool IsMultiPolygon(this ShapeType type)
{
    // 將其他 Polygon 類別歸到 MultiPolygon
    return type == ShapeType.PolygonM
        || type == ShapeType.PolygonZM
        || type == ShapeType.PolygonZ;
}
```

#### ShpPolygonWriter.cs

將原本的 `ShpPolygonWriter.cs` 複製一份，其中一份改名成 `MultiPolygon`，剩下的那一份調整成 Polygon 的型別。這個地方負責的是寫入檔案，因此要把原本的寫法轉換成適合 Polygon 的樣子。

```C#
/// <summary>
/// Polygon SHP file writer.
/// </summary>
public class ShpPolygonWriter : ShpWriter<Polygon>
{
    /// <inheritdoc/>
    public ShpPolygonWriter(Stream shpStream, Stream shxStream, ShapeType type) : base(shpStream, shxStream, type)
    {
        if (!ShapeType.IsPolygon())
            ThrowUnsupportedShapeTypeException();
    }

    internal override void WriteGeometry(Polygon polygon, Stream stream)
    {
        var partsBuilder = new ShpMultiPartBuilder(1, 4);

        partsBuilder.AddPart(polygon.Shell.CoordinateSequence);
        partsBuilder.WriteParts(stream, HasZ, HasM);
        partsBuilder.UpdateExtent(Extent);
    }
}
```

#### ShapefilePolygonWriter.cs

將原本的 `ShapefilePolygonWriter.cs` 複製一份出來，其中一份修改成 MultiPolygon，另外一份則調整成 Polygon 的型別。

```C#
/// <summary>
/// Polygon shapefile writer.
/// </summary>
public class ShapefilePolygonWriter : ShapefileWriter<Polygon>  // 型別改成 Polygon
{
    /// <inheritdoc/>
    public ShapefilePolygonWriter(Stream shpStream, Stream shxStream, Stream dbfStream, ShapeType type, IReadOnlyList<DbfField> fields, Encoding encoding = null)
        : base(shpStream, shxStream, dbfStream, type, fields, encoding)
    { }

    /// <inheritdoc/>
    public ShapefilePolygonWriter(string shpPath, ShapeType type, IReadOnlyList<DbfField> fields, Encoding encoding = null, string projection = null)
        : base(shpPath, type, fields, encoding, projection)
    { }

    /// <inheritdoc/>
    public ShapefilePolygonWriter(string shpPath, ShapeType type, params DbfField[] fields)
        : base(shpPath, type, fields)
    {
    }

    internal override ShpWriter<Polygon> CreateShpWriter(Stream shpStream, Stream shxStream)
    {
        // 回傳 Polygon 的 Writer
        return new ShpPolygonWriter(shpStream, shxStream, ShapeType);
    }
}
```

#### `Shapefile.cs`

最後要調整的地方就是 `OpenWrite` 裡面的判斷，把 `IsPolygon()` 的部分獨立出來。

---

這個過程中最棘手的部分有兩個，一個是要確切地找出原因是甚麼，需要花費一點時間在爬 code；另外一個就是在寫入的地方，因為不確定底層怎麼實作的，所以煩惱了很久要怎麼調整，最後選擇參考 Multi Polygon 的寫法，把不需要的部分（Z point、迴圈）拿掉，幸好有成功 🎊

最後，這個部分我有拉了一個 fork 在[我自己的 GitHub](https://github.com/anthea-wu/NetTopologySuite.IO.Esri?ref=blog.anthea.day) 上，如果有需要的人可以參考一下喔 😄

---

#### 參考文章

- [NetTopologySuite.IO.Esri 官方 GitHub](https://github.com/NetTopologySuite/NetTopologySuite.IO.Esri?ref=blog.anthea.day)