为类型T编写扩展方法;如何为 T 的字段添加类型约束?
初始情况:
我正在使用专有框架(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
,在此包装类型上定义扩展方法,然后以某种方式将所有 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
根据定义,如果您有一个
IFeature
对象,则其Shape
属性可以包含实现IGeometry
的任何类型的值。如果您可以控制IFeature
对象的实例化,那么您可以创建自己的实现IFeature
的通用类,或者从实现IFeature
的框架类派生一个类>IFeature 然后您可以轻松约束Shape
的类型。如果您无法控制这些对象的实例化,那么您可能会陷入运行时检查的困境。如果您碰巧使用 .NET 4.0,那么您可以使用代码契约。如果您的扩展方法对
Shape
类型有先决条件,静态检查器会向您发出编译时警告。By definition, if you have an
IFeature
object then itsShape
property can contain a value of any type that implementsIGeometry
. If you're in control of instantiation of theIFeature
objects, then you can create your own generic class that implementsIFeature
or derive a class from a framework class that implementsIFeature
and then you can easily constrain the type ofShape
. 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
.使您的 IFeature 接口也通用:
然后您可以在 IFeature 的内部类型上设置一个约束。
Make your IFeature interface generic too:
Then you can set a constaint on the inner type of the IFeature.
我认为您无法使用 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.
我认为添加仅适合将功能指向 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.
有趣的问题,对我来说尤其是因为我(必须)以 ArcObjects 编程为生。
编辑,警告:这种方法不起作用。它会在运行时失败。我将把它留在这里感到羞愧。
采用 Sebastian PR Gingter 关于接口继承的建议并运行它,我定义了一个继承
IFeature< 的接口
IFeatureOf
/代码>。这个新界面的唯一好处是在声明功能时添加更多信息。但是,如果您事先知道您正在处理点要素,那么您可以将这些要素声明为
IFeatureOf
并将它们提供给需要包含点几何图形的要素的函数。当然,您仍然可以将面要素类中的要素声明为
var notReallyAPointFeature = (IFeatureOf)myPolygonFeature;
,但如果您提前知道要素类型并使用IFeatureOF<> ;
为了限制它,如果将其提供给专门的函数,则会出现编译时错误。下面的小例子:
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 inheritsIFeature
. 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 useIFeatureOF<>
to constrain it, you will get compile time errors if you feed it to specialized functions.Small example below: