初始情况:
我正在使用专有框架(ESRI的ArcGIS Engine),我希望通过一些新功能进行扩展。我选择在C#中使用扩展方法。
下面显示的是与此问题相关的框架API部分:
+------------------------+ IGeometry
| IFeature <interface> | <interface>
+------------------------+ ^
| +Shape: IGeometry | |
+------------------------+ +---------+---------+
| |
IPoint IPolygon
<interface> <interface>
我想做什么:
我想为IFeature
编写一个扩展方法,允许以下内容:
IFeature featureWithPointShape = ...,
featureWithPolygonShape = ...;
// this should work:
featureWithPointShape.DoSomethingWithPointFeature();
// this would ideally raise a compile-time error:
featureWithPolygonShape.DoSomethingWithPointFeature();
问题是点和多边形形状(IPoint
和IPolygon
)都包含在同一类型(IFeature
)中,为此定义了扩展方法。扩展方法必须在IFeature
上,因为我只能从IFeature
转到IGeometry
,反之则不然。
问题:
虽然可以在运行时轻松检查IFeature
对象Shape
的类型(请参阅下面的代码示例),但是如何在编译时实现此类型检查?
public static void DoSomethingWithPointFeature(this IFeature feature)
{
if (!(feature.Shape is IPoint))
{
throw new NotSupportedException("Method accepts only point features!");
}
... // (do something useful here)
}
(是否有可能使用IFeature
的通用包装类型,例如FeatureWithShape<IPoint>
,在此包装类型上定义扩展方法,然后以某种方式转换所有{{1}对象到这个包装器类型?)
答案 0 :(得分:1)
使您的IFeature界面也通用:
IFeature<IPoint>
IFeature<IPolygon>
然后你可以在IFeature的内部类型上设置一个constaint。
答案 1 :(得分:1)
根据定义,如果您有一个IFeature
对象,则其Shape
属性可以包含实现IGeometry
的任何类型的值。如果你控制IFeature
对象的实例化,那么你可以创建自己的通用类来实现IFeature
或者从实现IFeature
的框架类派生一个类然后你可以轻松约束Shape
的类型。如果您无法控制这些对象的实例化,那么您可能会遇到运行时检查。
如果您正在使用.NET 4.0,那么您可以使用代码合同。如果您的扩展方法具有Shape
类型的前提条件,则静态检查器会向您发出编译时警告。
答案 2 :(得分:1)
我认为您无法在编译时使用ArcObjects的IFeature接口实现此检查。
几何类型取决于加载要素的要素类的定义。直到运行时才会知道这一点。
答案 3 :(得分:1)
我认为添加一个扩展方法是一个糟糕的设计,它只适用于指向IFeature接口的功能。接口IFeature由所有类型的几何(点,线和多边形)实现。这意味着扩展方法还应设计为在扩展IFeature接口时支持所有类型的几何。事实显然不是这样: - )
当您必须扩展IFeature时,请在运行时检查形状类型,如您所写。在我看来,这是解决问题的最佳方案。
答案 4 :(得分:0)
有趣的问题,对我而言,特别是因为我(必须)用ArcObjects为生活而编程。
编辑,警告:此方法不起作用。它会在运行时失败。我会留在这里羞耻。
考虑到Sebastian P.R. Gingter建议的接口继承并运行它,我已经定义了一个继承IFeatureOf<T>
的接口IFeature
。这个新界面唯一有用的是在声明功能时添加更多信息。
但是,如果您事先知道要处理点要素,则可以将这些要素声明为IFeatureOf<IPoint>
,并将它们提供给期望包含点几何的要素的函数。
您当然可以将面要素类中的要素声明为var notReallyAPointFeature = (IFeatureOf<IPoint>)myPolygonFeature;
,但如果您事先知道要素类型并使用IFeatureOF<>
来约束它,则会出现编译时错误你把它喂给专门的职能部门。
下面的小例子:
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Geodatabase;
class Program
{
public interface IFeatureOf<T> : IFeature { };
public static void AcceptsAllFeatures(IFeature feature) {
//do something, not caring about geometry type...
return;
}
public static void AcceptsOnlyPointFeatures(IFeatureOf<IPoint> pointFeature) {
IPoint pointGeometry = (IPoint)pointFeature.Shape; //constraint guarantees this is OK
//do something with pointGeometry
return;
}
static void Main(string[] args)
{
IFeature pointFeature = new FeatureClass(); //this is where you would read in a feature from your data set
IFeature polylineFeature = new FeatureClass();
var constainedPointFeature = (IFeatureOf<IPoint>)pointFeature;
var constrainedPolylineFeature = (IFeatureOf<IPolyline>)polylineFeature;
AcceptsAllFeatures(constainedPointFeature); //OK
AcceptsAllFeatures(constrainedPolylineFeature); //OK
AcceptsAllFeatures(pointFeature); //OK
AcceptsAllFeatures(polylineFeature); //OK
AcceptsOnlyPointFeatures(constainedPointFeature); //OK
AcceptsOnlyPointFeatures(constrainedPolylineFeature); //Compile-time error: IFeatureOf<IPolyline> != IFeatureOf<IPoint>
AcceptsOnlyPointFeatures(pointFeature); //Compile-time error: IFeature != IFeatureOf<something>
AcceptsOnlyPointFeatures(polylineFeature); //Compile-time error: IFeature != IFeatureOf<something>
}
}