简体   繁体   English

将界面投射到混凝土类型

[英]Cast interface to concrete type

I am using the GeoJSON.NET library in my project. 我在我的项目中使用GeoJSON.NET库。 At some point I need to update a feature in my database. 在某些时候,我需要更新数据库中的功能。 As a part of this, I need to access the coordinates of said Feature in order to store that information in the database as well. 作为其一部分,我需要访问所述要素的坐标,以便将该信息也存储在数据库中。 However looking at the source code on GitHub, the Feature class has the Geometry property as an IGeometryObject: 但是,查看GitHub上的源代码,Feature类具有Geometry属性作为IGeometryObject:

 public IGeometryObject Geometry { get; set; }

There exist multiple "shapes" according to GeoJSON specification, such as "Polygon", "Circle", "Point", etc. These specific shapes have been set up within the GeoJSON.NET project. 根据GeoJSON规范,存在多个“形状”,例如“多边形”,“圆形”,“点”等。这些特定形状已在GeoJSON.NET项目中设置。

It's within those concrete types that I can actually dig in and access the various coordinates. 我可以在这些具体类型中进行实际挖掘并访问各种坐标。

Currently I have this: 目前我有这个:

    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;
}

And here is a snippet from the Polygon class: 这是Polygon类的摘录:

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

So here in my code I'm actually doing an explicit downcast to a Polygon as I need to get to the Coordinates member of the Polygon class. 因此,在我的代码中,实际上我正在对Polygon进行显式下调,因为我需要获取Polygon类的Coordinates成员。 I know I'm safe to do this only on the basis that these are the only "types" of shapes I'm using in my application, even though I know it's not necessarily best practice. 我知道仅基于这些是我在应用程序中使用的形状的唯一“类型”,就可以安全地这样做,即使我知道这不一定是最佳实践。 However in the future if we were to use other types, this would totally break. 但是,将来如果我们使用其他类型,则将完全中断。 I can go implement using "is or as" for type checking, but that still doesn't move me away from the notion of having to downcast. 我可以使用“ is或as”进行类型检查,但这仍然并没有使我摆脱必须垂头丧气的想法。

So my question is what is the best way to go about this? 所以我的问题是最好的方法是什么? I've read around about why to use interfaces and all that as members and/or parameters and that having to do an explicit downcast is "usually" bad practice and follows a bad design pattern... with the exception of rare cases. 我已经读过有关为什么使用接口以及将其全部用作成员和/或参数的信息,并且必须进行显式的向下转换是“通常”的不正确做法,并且遵循错误的设计模式……(除了极少数情况)。 So do I fall into the "rare cases" here or is there a better way to go about this? 那么,我是否属于“稀有案例”呢?还是有更好的方法来解决这个问题?

So you've decided you need to access an internal implementation detail of someone elses interface that you can't change. 因此,您已经决定需要访问无法更改的其他人接口的内部实现细节。

Then you really have no choice but to take the cost of future maintenance. 然后,您别无选择,只能承担将来的维护费用。 Yes, you have one of those rare cases.. 是的,您有其中一种罕见的情况。

To minimize the cost I strongly suggest you wrap all dangerous code in a helper class that operates on the published interface, so you don't mix it with your own business logic and clearly see where you need to make changes in the future. 为了最大程度地降低成本,我强烈建议您将所有危险代码包装在可运行于已发布界面上的帮助程序类中,以便不要将其与自己的业务逻辑混合在一起,并且清楚地看到将来需要进行更改的地方。

Based on the GeoJSON.NET API, I think you do fall into one of these "rare cases". 基于GeoJSON.NET API,我认为您确实属于这些“稀有案例”之一。 You have a few options for dealing with this: 您可以选择几种方法来处理此问题:

  1. Add a switch statement to your CreateFeature method that dispatches to a shape-specific method. 在您的CreateFeature方法中添加一个switch语句,该语句将分派到特定于形状的方法。 Move the shape-specific functionality into the shape-specific method (see below). 将特定于形状的功能移至特定于形状的方法中(请参见下文)。
  2. Create a series of if..else if that do type checking for specific types (eg if (shape is Polygon) ProcessShape((Polygon)shape); ), and dispatch to a shape-specific method. 创建一系列if..else if来进行特定类型的类型检查(例如, if (shape is Polygon) ProcessShape((Polygon)shape); ),然后分派到特定于形状的方法。
  3. Use the visitor pattern to dispatch to a shape-specific method (although this would require that you modify the code of the GeoJSON.NET library). 使用访问者模式可以调度到特定于形状的方法(尽管这需要您修改GeoJSON.NET库的代码)。

Sample code for option 1: 选项1的示例代码

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

Sample code for option 3: 选项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);

...and if you go with option 3, submit a pull request on GitHub so that everyone can benefit from your improvements! ...如果您选择选项3,请在GitHub上提交拉取请求,以便每个人都可以从您的改进中受益!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM