Like the ‘using’ statement in C# which can import a namespace into the current source file, VB.NET has an equivalent one, ‘Imports’. After a namespace is used or imported in a source, the classes, interfaces, enums or any other types defined in the specific namespace do not have to be fully qualified anymore. Simply typing their base names should just work in case of no ambiguities.
For example, if the following Imports statement is put at the top of a VB.NET source file:
Imports Autodesk.Revit.DB
the BuiltInCategory, WallKind and StorageType enums, for example, can be declared this way:
Dim oo As BuiltInCategory
Dim mm As CoordinatePlaneVisibility
Dim bb As WallKind
Dim jj As ExportPaperFormat
Dim cc As StorageType
Dim dd As ImportUnit
Dim ee As HiddenLineViewsType
It’s good since the code becomes concise and it does not seem the .NET Framework or any other APIs define the same things somewhere else.
So far so good! Let’s try some more:
Dim nn As ChangePriority
Dim aa As ZoomType
Dim ff As HorizontalAlignmentStyle
Dim gg As GridSegmentDirection
Dim hh As FitDirectionType
Dim ii As FamilyHostingBehavior
Dim kk As DimensionStyleType
Dim ll As DigitGroupingAmount
OH, NO!
This time, the intellisense will under-wave-line all these types and tooltip something like, “'ChangePriority' is not accessible in this context because it is 'Friend'.”, if cursor is hovering on the code.
If we build the project, as expected, the following error messages will be output:
Error 1 'ChangePriority' is not accessible in this context because it is 'Friend'. C:\Temp\TestFriendOrNot\ExtCmd.vb 94 23 TestFriendOrNot
Error 2 'ZoomType' is not accessible in this context because it is 'Friend'. C:\Temp\TestFriendOrNot\ExtCmd.vb 95 23 TestFriendOrNot
Error 3 'HorizontalAlignmentStyle' is not accessible in this context because it is 'Friend'. C:\Temp\TestFriendOrNot\ExtCmd.vb 96 23 TestFriendOrNot
Error 4 'GridSegmentDirection' is not accessible in this context because it is 'Friend'. C:\Temp\TestFriendOrNot\ExtCmd.vb 97 23 TestFriendOrNot
Error 5 'FitDirectionType' is not accessible in this context because it is 'Friend'. C:\Temp\TestFriendOrNot\ExtCmd.vb 98 23 TestFriendOrNot
Error 6 'FamilyHostingBehavior' is not accessible in this context because it is 'Friend'. C:\Temp\TestFriendOrNot\ExtCmd.vb 99 23 TestFriendOrNot
Error 7 'DimensionStyleType' is not accessible in this context because it is 'Friend'. C:\Temp\TestFriendOrNot\ExtCmd.vb 100 23 TestFriendOrNot
Error 8 'DigitGroupingAmount' is not accessible in this context because it is 'Friend'.
If some classes are tried, similar things will happen.
Declarations:
'''' Some Classes
''
'' Just Good
'
Dim wal As Wall
Dim e4 As SlabEdge
Dim e5 As View3D
Dim e9 As SweepProfile
Dim e10 As SpotDimension
Dim e11 As SlabEdgeTypeSet
Dim e12 As ReferencePlane
Dim e13 As PrintSetting
'' Friend good? 'ThisType' is not accessible in this context because it is 'Friend'. :=(
'
Dim e6 As TransactionGroup
Dim e7 As TextNote
Dim e8 As TableData
Dim e0 As Element
Dim e1 As CurtainGrid
Dim e2 As FamilyInstance
Dim e3 As SketchPlane
Intellisense:
C:\Temp\TestFriendOrNot\ExtCmd.vb 101 23 TestFriendOrNot
Error 9 'TransactionGroup' is not accessible in this context because it is 'Friend'. C:\Temp\TestFriendOrNot\ExtCmd.vb 119 23 TestFriendOrNot
Error 10 'TextNote' is not accessible in this context because it is 'Friend'. C:\Temp\TestFriendOrNot\ExtCmd.vb 120 23 TestFriendOrNot
Error 11 'TableData' is not accessible in this context because it is 'Friend'. C:\Temp\TestFriendOrNot\ExtCmd.vb 121 23 TestFriendOrNot
Error 12 'Element' is not accessible in this context because it is 'Friend'. C:\Temp\TestFriendOrNot\ExtCmd.vb 122 23 TestFriendOrNot
Error 13 'CurtainGrid' is not accessible in this context because it is 'Friend'. C:\Temp\TestFriendOrNot\ExtCmd.vb 123 23 TestFriendOrNot
Error 14 'FamilyInstance' is not accessible in this context because it is 'Friend'. C:\Temp\TestFriendOrNot\ExtCmd.vb 124 23 TestFriendOrNot
Error 15 'SketchPlane' is not accessible in this context because it is 'Friend'.
Ok, now some interfaces:
'''' Some Interfaces
''
'' Just Good
'
Dim int1 As IFamilyLoadOptions
Dim int8 As IConnector
Dim int9 As IExtension
Dim int7 As IViewSheetSet
Dim int2 As IFCVersion
Dim int3 As ImportUnit
Dim int5 As IPrintSetting
'' Friend good? 'ThisType' is not accessible in this context because it is 'Friend'. :=(
'
Dim int6 As IUpdater
Dim int4 As ITransactionFinalizer
Dim int10 As IFailuresPreprocessor
Dim int11 As IFailuresProcessor
Intellisense:
Compiler errors:
C:\Temp\TestFriendOrNot\ExtCmd.vb 125 23 TestFriendOrNot
Error 16 'IUpdater' is not accessible in this context because it is 'Friend'. C:\Temp\TestFriendOrNot\ExtCmd.vb 140 25 TestFriendOrNot
Error 17 'ITransactionFinalizer' is not accessible in this context because it is 'Friend'. C:\Temp\TestFriendOrNot\ExtCmd.vb 141 25 TestFriendOrNot
Error 18 'IFailuresPreprocessor' is not accessible in this context because it is 'Friend'. C:\Temp\TestFriendOrNot\ExtCmd.vb 142 26 TestFriendOrNot
Error 19 'IFailuresProcessor' is not accessible in this context because it is 'Friend'. C:\Temp\TestFriendOrNot\ExtCmd.vb 143 26 TestFriendOrNot
So, what’s going on here?
The error messages indicated that some types are defined as protected or Friend in the Revit API assemblies and we were trying to use them in our assemblies thus the VB.NET compiler was not happy. But it’s not the case here. All types in the above code are public. Then there must be something wrong with the VB.NET IDE and compiler.
Q: Could not be something wrong with the Revit API?
A: Not likely based on the fact that the same code works perfectly fine in C#.
Q: Could it be that some types of the Revit API are public when referenced into a C# project but become Friend/protected when in a VB.NET project?
A: No way that I can think of. The involved enums, classes and interfaces are all public reflected from both the API documentation and object model.
Some people might say something like the Imports is not really a VB.NET statement, it is not supposed to work the same way that the C# ‘using’ works, and we should avoid using the Imports in VB.NET.
WRONG! If it were true, all the type declarations should have failed. In addition, from the following official MSDN explanations about the Imports statement in VB.NET, it is crystal clear that this ‘Imports’ in VB.NET should behave exactly the same as that ‘using’ in C#.
“Note that the Imports statement does not make elements from other projects and assemblies available to your project. Importing does not take the place of setting a reference. It only removes the need to qualify names that are already available to your project.”
“The scope of the elements made available by an Imports statement depends on whether you specify element. If you specify only namespace, all uniquely named members of that namespace, and members of container elements within that namespace, are available without qualification. If you specify both namespace and element, only the members of that element are available without qualification.”
“Code outside a namespace or container element must normally qualify a member's name with the name of that namespace of container element. The Imports statement makes such qualification unnecessary unless your project has access to another member with the same name. In such a case you can specify an aliasname in each Imports statement. Then you need only the import aliases to qualify the members with the same name.”
“If you use the Imports statement without an alias, you can use all the names in that namespace without qualification, provided they are unique to the project. If your project contains Imports statements for namespaces that contain items with the same name, you must fully qualify that name when you use it.”
Ok, now resolutions. Are there any?
Yes and not only one.
One can be done at the project level, turning on the necessary ‘Imported namespaces’ in the following checkable list box of the References tab in the Project Properties dialog of the VB.NET IDE:
After this is done, all the type declarations in the code mentioned earlier will look and compile just fine. No need to remove the Import statements from the files or make any changes to the code itself at all. Of course, if some types from some other namespaces such as Autodesk.Revit.UI are going to be used, please find those ‘Imported namespaces’ in the same place and check them off as well.
The other solution applies to code line, using fully qualified names for those declarations not recognized by VB.NET.
Personally, I am for the second solution:
- Not every type declaration has this problem. Many others behave just well.
- The same code works anywhere any time.
- It is good for sharing. If the code is posted to web and people download it, they do not have trouble to compile it.
- Easy for code porting from VB.NET to C# as there is not such a thing as project level Imported Namespaces in C# IDE.
- Make coding style consistent in both C# and VB.NET.
- The problem would not be there forever, I believe. There will be some day that it is resolved from the VB.NET end.
- The first solution uses a different feature to work around an issue in another feature. In fact, it totally ignores the Imports statement of VB.NET.
RevitAddinWizard realized this issue and applied the second solution into its various wizards, coders, and widgets as far as VB.NET is concerned.
Recent Comments