将接口转换为具体类型

时间:2016-06-10 15:04:01

标签: c# .net interface casting geojson

我在我的项目中使用GeoJSON.NET库。在某些时候,我需要更新我的数据库中的功能。作为其中的一部分,我需要访问所述功能的坐标,以便将该信息存储在数据库中。无论在GitHub上查看源代码,Feature类都将Geometry属性作为IGeometryObject:

 public IGeometryObject Geometry { get; set; }

存在多种形状"根据GeoJSON规范,例如" Polygon"," Circle"," Point"等。这些特定形状已在GeoJSON.NET项目中设置。

在我可以实际挖掘并访问各种坐标的那些具体类型中。

目前我有这个:

    public int CreateFeature(Feature feature)
    {
        int featureId = 0;
        var coordinatesDt = new DataTable();
        coordinatesDt.Columns.Add("Latitude");
        coordinatesDt.Columns.Add("Longitude");

        //we are loading a datatable with the coordinates.  This gets passed to a SQL server stored procedure as a single parameters to insert
        //all the nodes.
        LineString lineString = ((Polygon)feature.Geometry).Coordinates[0];
        foreach (var coordinate in lineString.Coordinates)
        {
            var row = coordinatesDt.NewRow();
            row["Latitude"] = ((GeographicPosition)coordinate).Latitude;
            row["Longitude"] = ((GeographicPosition) coordinate).Longitude;
            coordinatesDt.Rows.Add(row);
        }


        using (SqlConnection conn = new SqlConnection(_smmConnectionString))
        using (SqlCommand cmd = new SqlCommand("dbo.MyProc", conn))
        {
            //set up params, set up TVP and execute...
        }
        return featureId;
}

以下是Polygon类的片段:

public List<LineString> Coordinates { get; set; }

所以在我的代码中我实际上是在向Polygon进行显式向下转换,因为我需要到Polygon类的Coordinates成员。我知道只有在这些是唯一的&#34;类型的基础上我才能安全地做到这一点。在我的应用程序中使用的形状,即使我知道它不一定是最佳实践。然而,如果我们将来使用其他类型,这将完全打破。我可以使用&#34; is或as&#34;对于类型检查,但仍然没有让我远离不得不贬低的概念。

所以我的问题是,最好的方法是什么?我已经读过为什么要使用接口以及所有这些作为成员和/或参数,并且必须进行明确的向下转换是&#34;通常&#34;糟糕的做法,并遵循一个糟糕的设计模式......除了罕见的情况。那么我是否会陷入罕见的情况&#34;在这还是有更好的方法来解决这个问题?

2 个答案:

答案 0 :(得分:1)

因此,您已经决定需要访问您无法更改的其他人界面的内部实施细节。

然后你别无选择,只能承担未来维护的费用。是的,你有一个罕见的情况..

为了最大限度地降低成本,我强烈建议您将所有危险代码包装在一个在已发布界面上运行的帮助程序类中,这样您就不必将它与您自己的业务逻辑混合,并清楚地看到您需要在哪里进行更改未来。

答案 1 :(得分:1)

基于GeoJSON.NET API,我认为你确实属于其中一个&#34;罕见的情况&#34;。你有几个选择来解决这个问题:

  1. 将switch语句添加到CreateFeature方法,该方法将调度到特定于形状的方法。将特定于形状的功能移动到特定于形状的方法中(参见下文)。
  2. 创建一系列if..else,如果它确定类型检查特定类型(例如if (shape is Polygon) ProcessShape((Polygon)shape);),并调度到特定于形状的方法。
  3. 使用访问者模式调度到特定于形状的方法(尽管这需要您修改GeoJSON.NET库的代码)。
  4. 选项1的示例代码:

    switch (shape.Type)
    {
        case GeoJSONObjectType.Polygon:
            ProcessShape((Polygon)shape);
            break;
        // additional shape support here...
    }
    

    选项3的示例代码:

    // Add an AcceptVisitor method to the IGeometryObject interface:
    public interface IGeometryObject
    {
        GeoJSONObjectType Type { get; }
        void AcceptVisitor(IShapeProcessor visitor);
    }
    // Update each concrete shape class to include the new AcceptVisitor method:
    public void AcceptVisitor(IShapeProcessor visitor)
    {
        visitor.ProcessShape(this);
    }
    // Add an IShapeProcessor interface to the GeoJSON.NET project:
    public interface IShapeProcessor
    {
        void ProcessShape(Polygon shape);
        void ProcessShape(MultiPoint shape);
        void ProcessShape(LineString shape);
        // ...additional shape support...
    }
    // Update your existing class to implement the IShapeProcessor interface,
    // and then change your code to do something like:
    feature.Geometry.AcceptVisitor(this);
    

    ...如果您使用选项3,请在GitHub上提交拉取请求,以便每个人都可以从您的改进中受益!