可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
So the ExternalDefinitionCreationOptions had a spelling error in the Revit 2015 API that was corrected in the 2016 API.
I try to make my app as compatible as possible with the current version + previous, but this time I'm not even able to compile it since I can only reference one of the two API DLL's, and the ExternalDefinitionCreationOptions
plays a big role in the process.
The code is the following:
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;
}
I'm reading about DI and IoC, but all the samples have all the code under control, not referencing a third-party API and dealing with it. I've run out of ideas.
Any thoughts on how to accomplish this?
回答1:
The dynamic in C# allow you to use late-binding. Then I would suggest some reflection to instante the object, like the "logic" below (not tested, needs to be completed)
Type t = System.Reflection.Assembly.GetExecutingAssembly().GetType("ExternalDefinitionCreationOptions");
dynamic defOptions = t.GetConstructor().Invoke();
Note that dynamic is different from var. Your code is using var just as a way to let the compiler decide the type... now dynamic will only define the type on runtime.
回答2:
Using the base code from Augusto (upvoted) and a lot more research on Reflection I was able to write this solution:
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 });
回答3:
Why not use conditional compilation?
#if REVIT2015
var defOptions = new ExternalDefinitonCreationOptions(name, parameterType);
#else
var defOptions = new ExternalDefinitionCreationOptions(name, parameterType);
#endif
You have to define a REVIT2015 conditional compilation symbol in your Revit 2015 project (Project options, Build tab).
Of course, this only work if you have two separate VS projects, with a source project and a project where files are linked to the files in the source project.
回答4:
i fully agree with maxence' approach above.
i also suggest placing all conditional compilation into one single compatibility module and exporting its functionality as methods or properties, e.g. by defining a method like this:
ExternalDefinitionCreationOptions
NewExternalDefinitionCreationOptions(
string name,
ParameterType parameterType )
{
#if REVIT2015
return new ExternalDefinitonCreationOptions(name, parameterType);
#else // if not REVIT2015
return new ExternalDefinitionCreationOptions( name, parameterType );
#endif // REVIT2015
}
i implemented this here:
https://github.com/jeremytammik/the_building_coder_samples/blob/master/BuildingCoder/BuildingCoder/Util.cs#L1209-L1225
have fun!
cheers
jeremy
回答5:
Updated answer for handling both Revit 2015 and Revit 2016 API within the same add-in.
Do you really want to do that?
Well, if you insist, here goes:
#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
Usage:
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 );
Untested!
Cheers,
Jeremy