代码之家  ›  专栏  ›  技术社区  ›  stakx - no longer contributing Saravana Kumar

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

  •  3
  • stakx - no longer contributing Saravana Kumar  · 技术社区  · 14 年前

    初始情况:

    我正在使用一个专有框架( ESRI ArcGIS Engine )我想用一些新的功能来扩展它。为此,我选择了在C#中使用扩展方法。

        +------------------------+                   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公司 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> ,在此包装器类型上定义扩展方法,然后以某种方式将 对象到这个包装器类型?)

    5 回复  |  直到 12 年前
        1
  •  1
  •   Jack Leitch    14 年前

    根据定义,如果你有 IFeature 对象然后它的 Shape 属性可以包含实现的任何类型的值 IGeometry . 如果您控制 IFeature公司 对象,然后可以创建自己的实现 IFeature公司 然后就可以很容易地约束 形状 . 如果您不能控制这些对象的实例化,那么您可能会被一个运行时检查卡住。

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

        2
  •  1
  •   Sebastian P.R. Gingter    14 年前

    使IFeature界面也通用:

    IFeature<IPoint>
    IFeature<IPolygon>
    

    然后可以设置IFeature的内部类型。

        3
  •  1
  •   Neil Duxbury    14 年前

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

        4
  •  1
  •   dr pain    13 年前

    我认为在IFeature接口中添加只适合点特征的扩展方法是一个糟糕的设计。接口IFeature由所有类型的几何体(点、线和多边形)实现。这意味着在扩展IFeature接口时,扩展方法还应设计为支持所有类型的几何图形。情况显然不是这样:-)

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

        5
  •  0
  •   cfern    14 年前

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

    根据Sebastian P.R.ginger关于接口继承的建议,并使用它运行,我定义了一个接口 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>
        }
    }