C# 编写T型的扩展方法;如何为T字段添加类型约束?

C# 编写T型的扩展方法;如何为T字段添加类型约束?,c#,extension-methods,typechecking,arcobjects,type-constraints,C#,Extension Methods,Typechecking,Arcobjects,Type Constraints,初始情况: 我正在使用一个专有框架,我想用一些新功能扩展它。为此,我选择在C#中使用扩展方法 以下是框架API中与此问题相关的部分: +------------------------+ IGeometry | IFeature <interface> | <interface> +------------------------+

初始情况:

我正在使用一个专有框架,我想用一些新功能扩展它。为此,我选择在C#中使用扩展方法

以下是框架API中与此问题相关的部分:

    +------------------------+                   IGeometry
    |  IFeature <interface>  |                   <interface>
    +------------------------+                       ^
    |  +Shape: IGeometry     |                       |
    +------------------------+             +---------+---------+
                                           |                   |
                                        IPoint              IPolygon
                                        <interface>         <interface>
问题在于,点和多边形形状(
IPoint
IPolygon
)都包装在同一类型(
IFeature
)中,并为其定义了扩展方法。扩展方法必须启用
IFeature
,因为我只能从
IFeature
获取其
IGeometry
,反之亦然


问题:

虽然可以在运行时轻松检查
IFeature
对象的
形状的类型(请参见下面的代码示例),但如何在编译时实现此类型检查

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
,定义此包装类型上的扩展方法,然后以某种方式将所有
IFeature
对象转换为此包装类型?

也使IFeature接口通用:

IFeature<IPoint>
IFeature<IPolygon>
IFeature
IFeature

然后可以在IFeature的内部类型上设置约束。

根据定义,如果您有一个
IFeature
对象,则其
Shape
属性可以包含实现
IGeometry
的任何类型的值。如果您控制
IFeature
对象的实例化,那么您可以创建自己的实现
IFeature
的泛型类,或者从实现
IFeature
的框架类派生一个类,然后您可以轻松地约束
形状的类型。如果您不能控制这些对象的实例化,那么您可能会被运行时检查所困扰


如果您碰巧使用的是.NET4.0,那么您可以使用代码契约。如果扩展方法对
Shape

类型有一个先决条件,那么静态检查器将在编译时向您发出警告,这对我来说是一个有趣的问题,尤其是因为我(不得不)以使用ArcObjects编程为生

编辑,警告:此方法无效。它将在运行时失败。我会丢下它的

根据Sebastian p.R.Ginger关于接口继承的建议并使用它运行,我定义了一个接口
IFeatureOf
,它继承了
IFeature
。这个新接口唯一的好处就是在声明特性时添加更多信息

但是,如果您事先知道正在处理点要素,则可以将这些要素声明为
IFeatureOf
,并将其提供给需要包含点几何图形的要素的函数

当然,您仍然可以将多边形要素类中的要素声明为
var notrealyapointfeature=(IFeatureOf)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>
    }
}
使用ESRI.ArcGIS.Geometry;
使用ESRI.ArcGIS.Geodatabase;
班级计划
{
公共接口IFeatureOf:IFeature{};
公共静态要素(IFeature要素){
//做点什么,不关心几何体类型。。。
返回;
}
公共静态void接受OnlyPointFeatures(IFeatureOf pointFeature){
IPoint pointGeometry=(IPoint)pointFeature.Shape;//约束保证这是正常的
//用点几何做点什么
返回;
}
静态void Main(字符串[]参数)
{
IFeature pointFeature=new FeatureClass();//这是从数据集中读入要素的位置
IFeature polylineFeature=新FeatureClass();
var constainedPointFeature=(IFeatureOf)pointFeature;
var constrainedPolylineFeature=(IFeatureOf)polylineFeature;
AcceptsAllFeatures(constainedPointFeature);//确定
AcceptsAllFeatures(constrainedPolylineFeature);//确定
AcceptsAllFeatures(pointFeature);//确定
AcceptsAllFeatures(polylineFeature);//确定
AcceptsOnlyPointFeatures(constainedPointFeature);//确定
AcceptsOnlyPointFeatures(constrainedPolylineFeature);//编译时错误:IFeatureOf!=IFeatureOf
AcceptsOnlyPointFeatures(pointFeature);//编译时错误:IFeature!=IFeatureOf
AcceptsOnlyPointFeatures(polylineFeature);//编译时错误:IFeature!=IFeatureOf
}
}

我认为,使用ArcObjects的IFeature接口无法在编译时实现此检查


几何图形类型取决于从中加载特征的featureclass的定义。在运行时之前,您不会知道这一点。

我认为添加扩展方法是一种糟糕的设计,该方法仅适用于将要素指向IFeature接口。接口IFeature由所有类型的几何图形(点、线和多边形)实现。这意味着扩展方法还应设计为在扩展IFeature接口时支持所有类型的几何图形。情况显然并非如此:-)


当您必须扩展IFeature时,请在运行时检查形状类型,如您所写。在我看来,这是解决您问题的最佳解决方案。

我无法更改
IFeature
,因为它是专有框架的一部分。然后您可以这样做:MyFeature:IFeature-这样您就可以使用通用接口并进行完整的编译器检查,而您的泛型类型也是可以传递到框架的IFeature。感谢您迄今为止的输入。不幸的是,这也行不通,因为
IFeature
对象是由框架创建的。
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>
    }
}