Свойство IsShared для класса FamilyParameter
Довольно давно мы обсуждали способ как получить доступ к идентификатору общего параметра семейства (GUID) с помощью рефлексии. Если вы новичок в данном вопросе, вы можете ознакомиться с более подробной статьей Reflection in .NET на сайте CodeProject (на англ.).
Виктор Чекалин также столкнулся с этой проблемой и предложил более элегантное решение.
Ниже представлен наш диалог с обсуждением проблемы.
Вопрос: Почему класс FamilyParameter не имеет свойства IsShared, так же как и класс Parameter? Мне нужно получить всех параметров семейства, все их свойства и значения, включая GUID.
Сейчас, когда я пытаюсь получить значения свойства GUID объекта класса FamilyParameter и при этом параметр не является общим, Revit выбрасывает исключение InvalidOperationException. Единственный способ, как я могу узнать является ли параметр общим или нет, попытаться получить значение свойства GUID и обработать исключение, если параметр не общий.
Проблема в том, что перехват исключения является дорогостоящей операций и занимает относительно много времени. Если семейство содержит большое количество параметров, то программа ощутимо подтормаживает и «зависает».
Почему разработчика API реализовали такое довольно странное поведение и не добавили свойство IsShared в класс FamilyParameter? Можно ведь было возвращать null, если параметр не является общим, а не выбрасывать исключение.
Ответ: Прошу прощения за столь странное поведение. Обойти это ограничение и получить доступ к этим параметром можно используя рефлексию.
Отклик на ответ: Да, кажется этот способ действительно может мне помочь.
Я посмотрел код RevitAPI.dll с помощью рефлектора и мне стало еще более непонятным почему разработчики Revit API не добавили свойство IsShared для FamilyParameter. Ведь класс FamilyParameter является всего лишь оберткой над классом Parameter и чтобы добавить свойство IsShared нужно написать всего лишь пару строк кода:
- public bool IsShared
- {
- get { return getParameter().IsShared; }
- }
Повторно прочитав вашу статью, я кажется понял, почему они так и не добавили это свойство. Свойства GUID и IsShared были добавлены в класс Parameter только в Revit 2011. Могу предположить что это простая оплошность и они забыли добавить новые свойства также и в класс FamilyParameter. Возможно я ошибаюсь.
Надеюсь это свойство будет добавлено в следующих версиях API. Насколько я вижу в комментариях к статье, не только я ожидаю свойство IsShared.
Реализация метода-расширения IsShared для класса FamilyParameter
Основываясь на вашем примере в статье, я написал простой метод-расширение:
- public static bool IsShared(
- this FamilyParameter familyParameter )
- {
- MethodInfo mi = familyParameter
- .GetType()
- .GetMethod( "getParameter",
- BindingFlags.Instance
- | BindingFlags.NonPublic );
- if( null == mi )
- {
- throw new InvalidOperationException(
- "Could not find getParameter method" );
- }
- var parameter = mi.Invoke( familyParameter,
- new object[] { } ) as Parameter;
- return parameter.IsShared;
- }
Я использовал внутренний метод getParameter вместо поля m_Parameter, так как не рекомендуется обращаться к полям класса из другого класса. Также этот метод используется в коде в большинстве случаев, которые я видел используя рефлектор, а не поле m_Parameter.
Использование метода-расширения
Использование нового метода довольно очевидно:
- foreach( FamilyParameter fp in mgr.Parameters )
- {
- if( fp.IsShared() )
- {
- familyTypeParameter.Guid = fp.GUID;
- }
- }
Метод работает гораздо быстрее чем обработка и перехват исключения, например так:
- try { var guid = parameter.GUID; }
- catch() {}
Спасибо еще раз, что напомнил мне о рефлексии.
Ответ: Большое спасибо, Виктор, за исследование, отличную реализацию и что поделился с нами своим решением.
Источник: http://thebuildingcoder.typepad.com/blog/2012/09/familyparameter-isshared-property.html
Обсуждение: http://adn-cis.org/forum/index.php?topic=115.0
Отредактировано 19.07.2013 в 10:51:02