Search code examples
c#extension-methodstypecheckingarcobjectstype-constraints

Writing an extension method for type T; how can I add a type constraint for a field of T?


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?)


Solution

  • 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.