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

发布于 2024-09-07 17:46:27 字数 2002 浏览 14 评论 0原文

初始情况:

我正在使用专有框架(ESRIArcGIS 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();

问题在于点形状和多边形形状(IPointIPolygon)都包装在同一类型 (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,在此包装类型上定义扩展方法,然后以某种方式将所有 IFeature 对象转换为此包装类型?)

Initial situation:

I am working with a proprietary framework (ESRI's ArcGIS Engine) which I want to extend with some new functionality. I've chosen to use extension methods in C# for this.

Shown below are the parts of the framework API that are relevant to this question:

    +------------------------+                   IGeometry
    |  IFeature <interface>  |                   <interface>
    +------------------------+                       ^
    |  +Shape: IGeometry     |                       |
    +------------------------+             +---------+---------+
                                           |                   |
                                        IPoint              IPolygon
                                        <interface>         <interface>

What I want to do:

I want to write an extension method for IFeature that will allow the following:

IFeature featureWithPointShape   = ...,
         featureWithPolygonShape = ...;

// this should work:
featureWithPointShape.DoSomethingWithPointFeature();

// this would ideally raise a compile-time error:
featureWithPolygonShape.DoSomethingWithPointFeature();

The problem is that both point and polygon shapes (IPoint and IPolygon) are wrapped in the same type (IFeature), for which the extension method is defined. The extension method has to be on IFeature because I can only get from an IFeature towards its IGeometry, but not vice versa.


Question:

While the type of an IFeature object's Shape can easily be checked at run-time (see code example below), how could I achieve this type check at compile-time?

public static void DoSomethingWithPointFeature(this IFeature feature)
{
    if (!(feature.Shape is IPoint))
    {
        throw new NotSupportedException("Method accepts only point features!");
    }
    ...  // (do something useful here)
}

(Is there possibly any way to use a generic wrapper type for IFeature, e.g. FeatureWithShape<IPoint>, define the extension method on this wrapper type, and then somehow turn all IFeature objects into this wrapper type?)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

ぽ尐不点ル 2024-09-14 17:46:27

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

如果您碰巧使用 .NET 4.0,那么您可以使用代码契约。如果您的扩展方法对 Shape 类型有先决条件,静态检查器会向您发出编译时警告。

By definition, if you have an IFeature object then its Shape property can contain a value of any type that implements IGeometry. If you're in control of instantiation of the IFeature objects, then you can create your own generic class that implements IFeature or derive a class from a framework class that implements IFeature and then you can easily constrain the type of Shape. If you're not in control of instantiation of these objects, then you're probably stuck with a run-time check.

If you happen to be using .NET 4.0, then you could use code contracts. The static checker would give you a compile-time warning if your extension method had a pre-condition on the type of Shape.

忆离笙 2024-09-14 17:46:27

使您的 IFeature 接口也通用:

IFeature<IPoint>
IFeature<IPolygon>

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

Make your IFeature interface generic too:

IFeature<IPoint>
IFeature<IPolygon>

Then you can set a constaint on the inner type of the IFeature.

东北女汉子 2024-09-14 17:46:27

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

几何类型取决于加载要素的要素类的定义。直到运行时你才会知道这一点。

I don't think you can achieve this check at compile time with the IFeature interface from ArcObjects.

The geometry type depends on the definition of the featureclass that the feature is loaded from. You won't know this until run-time.

久隐师 2024-09-14 17:46:27

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

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

I think it is a bad design to add an extension method which is only appropiate to point features to the IFeature interface. The interface IFeature is implemented by all types of geometries (points, lines ans polygons). This means the extension method should also be designed to support all types of geometries when extending the IFeature interface. This is clearly not the case :-)

When you have to extend IFeature, then check for the shape type at runtime, as you have written. In my eyes, that is the best solution for your problem.

十年九夏 2024-09-14 17:46:27

有趣的问题,对我来说尤其是因为我(必须)以 ArcObjects 编程为生。

编辑,警告:这种方法不起作用。它会在运行时失败。我将把它留在这里感到羞愧。

采用 Sebastian PR Gingter 关于接口继承的建议并运行它,我定义了一个继承 IFeature< 的接口 IFeatureOf /代码>。这个新界面的唯一好处是在声明功能时添加更多信息。

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

当然,您仍然可以将面要素类中的要素声明为 var notReallyAPointFeature = (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>
    }
}

Interesting question, for me especially since I (have to) program with ArcObjects for a living.

Edit, warning: this approach doesn't work. It'll fail at runtime. I'll leave it here for shame.

Taking Sebastian P.R. Gingter's suggestion of interface inheritance and running with it, I've defined an interface IFeatureOf<T> that inherits IFeature. The only thing this new interface is good for, is adding more information when declaring Features.

But if you know in advance that you're dealing with point features, then you can declare these features as IFeatureOf<IPoint> and feed them to functions that expect features containing a point geometry.

You can of course still declare a feature from a polygon feature class as var notReallyAPointFeature = (IFeatureOf<IPoint>)myPolygonFeature;, but if you know the feature type in advance and use IFeatureOF<> to constrain it, you will get compile time errors if you feed it to specialized functions.

Small example below:

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>
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文