Предлагаю здесь обмениваться опытом людям, которые программируют в ArcGIS под .Net или просто работают с ArcObjects. Думаю, это может быть интересно не только новичкам, но и более продвинутым разработчикам.
-----------------------------------
Попробую немного затронуть тему интерфейсов. Примеры на C#, но и на VB.Net многое выглядит аналогично.
Использование методов расширения (Extension methods).
Один из основных вопросов у начинающих разработчиков под ArcGIS связан с огромным числом интерфейсов. Их действительно много и их приходится запоминать, чтобы не копаться каждый раз в справке, ища соответствующий интерфейс по названию метода или по списку интерфейсов, которые реализует рассматриваемый объект. Но это только полбеды. Допустим, вы запомнили те интерфейсы, с которыми вы работаете наиболее часто. Но это не избавляет вас от того, что вам приходится постоянно приводить эти интерфейсы один к другому (которые иногда еще и находится в различных сборках). Конечно, в рамках архитектуры системы наличие всех этих интерфейсов, группирующих методы по функционалу, может выглядеть красиво и смотреться все это будет отлично проработанным решением, но в итоге программировать становится не всегда удобно. Хочется попробовать немного упростить работу.
К примеру, когда вы работаете с геометрией, вам приходится постоянно приводить интерфейсы один к другому, например к IProximityOperator, ICurve, ITopologicalOperator, IArea.
Вместо этого можно подключить свою библиотеку с готовыми методами расширения для "основных" интерфейсов. Для полигонов (PolygonClass) - под "основным" методом я подразумеваю IPolygon, для точек (PointClass) - IPoint и т.д.
И в этом случае получается не просто библиотека, а библиотека, которой действительно удобно пользоваться.
Для того, чтобы найти, скажем, центр масс полигона, вам больше не придется делать нечто вроде:
IArea pArea = pPolygon as IArea;
return pArea.Centroid;
вместо этого можно будет написать:
return pPolygon.GetCentroid();
где GetCentroid() - это метод расширения для интерфейса IPolygon, т.е. не стандартный метод от ESRI, а наш собственный, но привязанный к IPolygon.
Кстати говоря, в данном случае всё равно далеко не всем интуитивно понятно, что IArea - это тот самый интерфейс для поиска центра.
Здесь я добавил расширяющий метод для IGeometry (для точки он вернет себя же, для линии и полигона - центр). Т.к. IPolygon наследует IGeometry, то никакого приведения не требуется.
Интерфейс IPolygon можно расширить методом GetArea(), возвращающим значение площади, этот метод мне приходится тоже использовать достаточно часто. Останется перенести туда же метод LabelPoint и тогда можно забыть про IArea насовсем.
Методы вроде StartEditing(), StopEditOperation() можно прицепить к IFeatureLayer, скрывая логику получения Workspace.
К IFeatureCursor или ICursor можно добавить метод Release(), тогда для освобождения ресурсов не потребуется вспоминать и явно обращаться к Marshal, а достаточно будет работать именно с IFeatureCursor.
К IMap можно прицепить FindLayer(), чтобы не вспоминать про метод FindMapLayer() в IGPUtilities из соответствующего пространства имен.
И т.д.
Пример метода расширения:
public static double GetDistance(this IGeometry thisGeometry, IGeometry pGeometry)
{
return ((IProximityOperator)thisGeometry).ReturnDistance(pGeometry);
}
Ничего сложного, обычный статический метод с добавлением ключевого слова this для первого параметра, тип которого мы расширяем. И как видно из примеров, это будет не классический статический (static/shared) метод, а именно метод для экземпляров.
В выпадающем меню интеллисенса метод будет помечен специальным значком, и вы сразу сможете отличить ваш метод от стандартных. Можно давать методу комментарий на родном языке, что удобно.
Понятно, что нельзя абсолютно все пихать в "основные" интерфейсы, иначе с тем же успехом можно обходиться и вовсе без интерфейсов, а использовать класс напрямую. В этом случае получается огромный список методов и свойств, выбирать из такого списка довольно сложно (создайте экземпляр того же PolygonClass и посмотрите сколько у него разных методов). Поэтому в "основных" интерфейсах должно быть только то, что вы используете очень часто.
Конечно, в расширении есть и свои минусы. Это особенность языка C# 3.0 и официально для работы этих методов требуется framework 3.5. Хотя можно заставить их работать с более старыми версиями framework, используя вот такой хак:
http://www.c-sharpcorner.com/UploadFile/pcurnow/extmethods03242008070853AM/extmethods.aspx.
Т.е. нужно лишь добавить следующий код:
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly)]
public sealed class ExtensionAttribute : Attribute
{
}
}
Но есть и более важная проблема - расширяющие методы могут внести некоторую мешанину в "стройную" систему стандартных интерфейсов.
Перевешивают ли эти минусы в вашем случае - решайте сами.
Но использование такого подхода позволит вам реже обращаться к специализированным интерфейсам, позволит значительно быстрее писать код, который к тому же будет более простой и короткий, по которому будет легче ориентироваться, проводить рефакторинг.
Особенно это актуально, когда вам в очередной раз необходимо быстренько решить несложную, но достаточно типовую задачу - когда, например, требуется создать новую кнопку для ArcMap, которая бы находила на карте слой по его имени, проходила бы по всем записям слоя, проводила бы некоторый анализ и записывала бы куда-то результат или выводила отчет. Думаю многие писали подобное не раз. Действия часто одни и те же.
Дополнительно про расширяющие методы можно почитать тут:
http://msdn.microsoft.com/ru-ru/library/bb383977.aspx
http://msdn.microsoft.com/ru-ru/magazine/cc163317.aspx (для vb)
http://en.wikipedia.org/wiki/Extension_method
-------------------------------
Вопрос опытным разработчикам.
А что делаете вы при создании нового проекта первым делом? Создаёте и подключаете ли вы какие-нибудь собственные шорткаты, сниппеты именно для arcobjects? Пользуетесь ли вы стандартными? Пишете ли вы предварительно юнит-тесты для своего кода, непосредственно работающего с ArcObjects? С помощью mock-объектов или как?
Что делаете вы, чтобы упростить свою работу?