将接口转换为具体类型
Cast interface to concrete type
我在我的项目中使用 GeoJSON.NET 库。在某些时候,我需要更新数据库中的一项功能。作为其中的一部分,我需要访问所述特征的坐标,以便将该信息也存储在数据库中。然而,查看 GitHub 上的源代码,特征 class 将几何体 属性 作为 IGeometryObject:
public IGeometryObject Geometry { get; set; }
根据GeoJSON规范,存在多个"shapes",例如"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;
}
这里是多边形 class 的片段:
public List<LineString> Coordinates { get; set; }
所以在我的代码中,我实际上正在对多边形进行显式向下转换,因为我需要获取多边形的坐标成员 class。我知道我这样做是安全的,因为这些是我在我的应用程序中使用的唯一 "types" 形状,尽管我知道这不一定是最佳实践。但是,如果将来我们要使用其他类型,这将完全崩溃。我可以使用 "is or as" 来实现类型检查,但这仍然不能使我摆脱不得不向下转型的想法。
所以我的问题是解决此问题的最佳方法是什么?我已经了解了为什么要使用接口和所有这些作为成员 and/or 参数,并且必须进行显式向下转换是 "usually" 不好的做法并且遵循不好的设计模式......除了罕见的情况。那么我是落入"rare cases"这里还是有更好的方法来解决这个问题?
因此您决定需要访问您无法更改的其他人接口的内部实现细节。
那以后的维修费用你就真的没办法了。是的,你有一种罕见的情况..
为了最大限度地降低成本,我强烈建议您将所有危险代码包装在一个在已发布接口上运行的助手 class 中,这样您就不会将其与您自己的业务逻辑混在一起,并且可以清楚地看到您需要的地方以便在未来做出改变。
根据 GeoJSON.NET API,我认为你确实属于其中之一 "rare cases"。您有几种选择来处理此问题:
- 向您的 CreateFeature 方法添加一个 switch 语句,以分派到特定于形状的方法。将形状特定的功能移动到形状特定的方法中(见下文)。
- 创建一系列 if..else if 对特定类型进行类型检查(例如
if (shape is Polygon) ProcessShape((Polygon)shape);
),并分派给形状特定的方法。
- 使用访问者模式分派特定于形状的方法(尽管这需要您修改 GeoJSON.NET 库的代码)。
选项 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 上提交拉取请求,以便每个人都能从您的改进中受益!
我在我的项目中使用 GeoJSON.NET 库。在某些时候,我需要更新数据库中的一项功能。作为其中的一部分,我需要访问所述特征的坐标,以便将该信息也存储在数据库中。然而,查看 GitHub 上的源代码,特征 class 将几何体 属性 作为 IGeometryObject:
public IGeometryObject Geometry { get; set; }
根据GeoJSON规范,存在多个"shapes",例如"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;
}
这里是多边形 class 的片段:
public List<LineString> Coordinates { get; set; }
所以在我的代码中,我实际上正在对多边形进行显式向下转换,因为我需要获取多边形的坐标成员 class。我知道我这样做是安全的,因为这些是我在我的应用程序中使用的唯一 "types" 形状,尽管我知道这不一定是最佳实践。但是,如果将来我们要使用其他类型,这将完全崩溃。我可以使用 "is or as" 来实现类型检查,但这仍然不能使我摆脱不得不向下转型的想法。
所以我的问题是解决此问题的最佳方法是什么?我已经了解了为什么要使用接口和所有这些作为成员 and/or 参数,并且必须进行显式向下转换是 "usually" 不好的做法并且遵循不好的设计模式......除了罕见的情况。那么我是落入"rare cases"这里还是有更好的方法来解决这个问题?
因此您决定需要访问您无法更改的其他人接口的内部实现细节。
那以后的维修费用你就真的没办法了。是的,你有一种罕见的情况..
为了最大限度地降低成本,我强烈建议您将所有危险代码包装在一个在已发布接口上运行的助手 class 中,这样您就不会将其与您自己的业务逻辑混在一起,并且可以清楚地看到您需要的地方以便在未来做出改变。
根据 GeoJSON.NET API,我认为你确实属于其中之一 "rare cases"。您有几种选择来处理此问题:
- 向您的 CreateFeature 方法添加一个 switch 语句,以分派到特定于形状的方法。将形状特定的功能移动到形状特定的方法中(见下文)。
- 创建一系列 if..else if 对特定类型进行类型检查(例如
if (shape is Polygon) ProcessShape((Polygon)shape);
),并分派给形状特定的方法。 - 使用访问者模式分派特定于形状的方法(尽管这需要您修改 GeoJSON.NET 库的代码)。
选项 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 上提交拉取请求,以便每个人都能从您的改进中受益!