Написание метода расширения для типа T; Как я могу добавить ограничение типа для поля T?

StackOverflow https://stackoverflow.com/questions/3171130

Вопрос

Исходная ситуация:

Я работаю с проприетарными рамками (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<IPoint>, определите метод расширения на этом типе обертки, а затем как-то включить все IFeature объекты в эту обертку типа?)

Это было полезно?

Решение

По определению, если у вас есть IFeature объект тогда его Shape Свойство может содержать значение любого типа, которое реализует IGeometry. Отказ Если вы контролируете зрелищую атмосферу IFeature объекты, то вы можете создать свой собственный универсальный класс, который реализует IFeature или вывести класс из рамочного класса, который реализует IFeature и тогда вы можете легко ограничить тип Shape. Отказ Если вы не контролируете создание этих объектов, вы, вероятно, застряли с проверкой выполнения.

Если вы будете использовать .NET 4.0, то вы можете использовать кодовые контракты. Статический контроллер даст вам предупреждение о компиляции, если ваш метод расширения имел предварительное условие на типе Shape.

Другие советы

Сделайте свой интерфейс Ifeature Generic:

IFeature<IPoint>
IFeature<IPolygon>

Тогда вы можете установить концу по внутреннему типу Ifeature.

Я не думаю, что вы сможете достичь этой проверки во время компиляции с интерфейсом Ifeature от ArcObjects.

Тип геометрии зависит от определения FeatureClass, от которого загружается функция. Вы не будете знать это до выхода.

Я думаю, что это плохой дизайн для добавления метода расширения, который соответствует только точкам функции для интерфейса IFEATURE. Интерфейс Ifeature реализуется всеми типами геометрии (точек, линий ANS Polygons). Это означает, что метод расширения также должен быть разработан для поддержки всех типов геометрии при расширении интерфейса IFEATURE. Это явно не так :-)

Когда вы должны продлить IFEATURE, то проверьте тип формы во время выполнения, как вы написали. В моих глазах это лучшее решение для вашей проблемы.

Интересный вопрос, для меня, тем более, так как I (надо) программа с ArcObjects для жизни.

Редактировать, предупреждение: этот подход не работает. Это не удастся во время выполнения. Я оставлю это здесь для стыда.

Принимая предложение Sebastian Pr Gingter о наследстве интерфейса и бежать с ним, я определил интерфейс 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>
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top