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