Тот же код для создания параметров в Revit 2015 + 2016

Итак, ExternalDefinitionCreationOptions имел орфографическая ошибка в Revit 2015 API, исправленная в API 2016.

Я пытаюсь сделать свое приложение максимально совместимым с текущей версией + предыдущей, но на этот раз я даже не могу его скомпилировать, так как могу ссылаться только на одну из двух API DLL, а ExternalDefinitionCreationOptions играет большую роль в процесс.

Код следующий:

private static Definition GetSimpleParameterDefinition(UIApplication uiApp, Document doc, DefinitionGroup defGroup, string name)
{
    var definition = defGroup.Definitions.FirstOrDefault(d => d.Name == name);
    if (definition != null) return definition;

    var parameterType = ParameterType.Text;

    var defOptions = new ExternalDefinitionCreationOptions(name, parameterType);
    BuiltInCategory target = BuiltInCategory.OST_Furniture;
    var cat = doc.Settings.Categories.get_Item(target);

    var catSet = uiApp.Application.Create.NewCategorySet();
    catSet.Insert(cat);

    definition = defGroup.Definitions.Create(defOptions);

    return definition;
}

Я читаю о DI и IoC, но во всех примерах есть весь код под контролем, без ссылки на сторонний API и работы с ним. У меня закончились идеи.

Есть мысли о том, как это сделать?


person Israel Rodriguez    schedule 28.10.2015    source источник


Ответы (5)


dynamic в C # позволяет использовать позднее связывание. Затем я бы предложил немного подумать, чтобы создать экземпляр объекта, например, "логику" ниже (не проверено, необходимо завершить)

Type t = System.Reflection.Assembly.GetExecutingAssembly().GetType("ExternalDefinitionCreationOptions");
dynamic defOptions = t.GetConstructor().Invoke();

Обратите внимание, что динамический отличается от var. Ваш код использует var просто как способ позволить компилятору определять тип ... теперь динамический будет определять тип только во время выполнения.

person Augusto Goncalves    schedule 28.10.2015
comment
Привет, @AugustoGoncalves, это кажется отличным способом добиться этого, но GetExecutingAssembly() (также GetCallingAssembly()) не возвращают сборку RevitAPI, оба возвращают мою сборку. Я даже пробовал пробежать через стек, чтобы получить Revit, но безуспешно. Мое приложение работает в режиме инициализации Revit, поэтому я не знаю, является ли оно причиной того, что оно не работает так, как вы предложили. - person Israel Rodriguez; 28.10.2015

Используя базовый код от Augusto (проголосовало за) и много других исследований по Reflection, я смог написать это решение:

var assemblies = System.Reflection.Assembly.GetExecutingAssembly().GetReferencedAssemblies();
var assemblyName = assemblies.First(a => a.Name == "RevitAPI");
Assembly revitAssembly = Assembly.Load(assemblyName);

Type t = revitAssembly.GetType("Autodesk.Revit.DB.ExternalDefinitionCreationOptions"); // For Revit2016
if (t == null) t = revitAssembly.GetType("Autodesk.Revit.DB.ExternalDefinitonCreationOptions"); // For Revit2015

var types = new Type[1] { t };
var constructor = t.GetConstructors()[0];
dynamic defOptions = constructor.Invoke(new object[] { item.Name, parameterType });
person Israel Rodriguez    schedule 28.10.2015

Почему бы не использовать условную компиляцию?

#if REVIT2015
   var defOptions = new ExternalDefinitonCreationOptions(name, parameterType);
#else
   var defOptions = new ExternalDefinitionCreationOptions(name, parameterType);
#endif

Вы должны определить символ условной компиляции REVIT2015 в своем проекте Revit 2015 (Параметры проекта, вкладка «Сборка»).

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

person Maxence    schedule 29.10.2015
comment
Привет, @Maxence, я использую этот подход в различных других ситуациях с новыми функциями, которые относятся к одной версии, а не к другой. Но этот кейс был основной функцией продукта, мне нужно, чтобы он работал без условной компиляции. - person Israel Rodriguez; 29.10.2015
comment
да! это получает мой голос! Это именно тот ответ, который я имел в виду, просто прочитав резюме в полученном мной электронном письме. Таким образом, в ExternalDefinitionCreationOptions была орфографическая ошибка в Revit 2015 API, которая была исправлена ​​в API 2016. Я стараюсь сделать свое приложение максимально совместимым с текущей версией .... круто! - person Jeremy Tammik; 30.10.2015

Я полностью согласен с подходом Maxence, изложенным выше.

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

ExternalDefinitionCreationOptions
  NewExternalDefinitionCreationOptions(
    string name,
    ParameterType parameterType )
{
  #if REVIT2015
    return new ExternalDefinitonCreationOptions(name, parameterType);
  #else // if not REVIT2015
    return new ExternalDefinitionCreationOptions( name, parameterType );
  #endif // REVIT2015
}

я реализовал это здесь:

https://github.com/jeremytammik/the_building_coder_samples/blob/master/BuildingCoder/BuildingCoder/Util.cs#L1209-L1225

повеселись!

ваше здоровье

Джереми

person Jeremy Tammik    schedule 30.10.2015
comment
Привет @ Джереми, спасибо за ответ. Но как сделать так, чтобы этот класс Util без проблем работал в Revit 2015 и 2016 в одной и той же DLL? - person Israel Rodriguez; 30.10.2015
comment
ахаа, в той же DLL. хорошо, это исключает условную компиляцию. Однако есть еще одно простое решение: вы можете проверить свойство Application.VersionNumber, а затем вызвать соответствующий метод с помощью Invoke. - person Jeremy Tammik; 31.10.2015
comment
ДА! Решение Augusto было для меня отличным стартом, я просто опубликовал окончательное и рабочее решение после - person Israel Rodriguez; 31.10.2015

Обновленный ответ для обработки API Revit 2015 и Revit 2016 в одной надстройке.

Вы действительно хотите это сделать?

Что ж, если вы настаиваете, вот оно:

#region Compatibility fix for spelling error change
/// <summary>
/// Wrapper to fix a spelling error prior to Revit 2016.
/// </summary>
public class SpellingErrorCorrector
{
  static bool _in_revit_2015_or_earlier;
  static Type _external_definition_creation_options_type;

  public SpellingErrorCorrector( Application app )
  {
    _in_revit_2015_or_earlier = 0
      <= app.VersionNumber.CompareTo( "2015" );

    string s
      = _in_revit_2015_or_earlier
        ? "ExternalDefinitonCreationOptions"
        : "ExternalDefinitionCreationOptions";

    _external_definition_creation_options_type
      = System.Reflection.Assembly
        .GetExecutingAssembly().GetType( s );
  }

  object NewExternalDefinitionCreationOptions(
    string name,
    ParameterType parameterType )
  {
    object[] args = new object[] { 
      name, parameterType };

    return _external_definition_creation_options_type
      .GetConstructor( new Type[] { 
        _external_definition_creation_options_type } )
      .Invoke( args );
  }

  public Definition NewDefinition(
    Definitions definitions,
    string name,
    ParameterType parameterType )
  {
    //return definitions.Create( 
    //  NewExternalDefinitionCreationOptions() );

    object opt
      = NewExternalDefinitionCreationOptions(
        name,
        parameterType );

    return typeof( Definitions ).InvokeMember(
      "Create", BindingFlags.InvokeMethod, null,
      definitions, new object[] { opt } )
      as Definition;
  }
}
#endregion // Compatibility fix for spelling error change

Использование:

static Util.SpellingErrorCorrector
  _spellingErrorCorrector = null;

Application app = doc.Application;

if( null == _spellingErrorCorrector )
{
  _spellingErrorCorrector
    = new Util.SpellingErrorCorrector( app );
}

DefinitionGroup group = sharedParametersFile
    .Groups.Create( "Reinforcement" );

def = _spellingErrorCorrector.NewDefinition(
    group.Definitions, "ReinforcementParameter",
    ParameterType.Text );

Не проверено!

Ваше здоровье,

Джереми

person Jeremy Tammik    schedule 31.10.2015
comment
Спасибо, Джереми, это именно то, что я разработал несколько дней назад - ›stackoverflow.com/a/33401274/228160 - person Israel Rodriguez; 01.11.2015