Here’s my third installment on some of the differences between VBA and C# that you’ll encounter when using C# to program Inventor’s API. Here are links to the first and second posts.
Optional Arguments
Previous to C# 2010, C# didn’t support optional arguments so you need to provide every argument in a method call. If you’re already working with C# 2010 then you can ignore this section.
The thing that makes handling optional arguments in C# difficult is figuring out what value you need to supply to get the same default behavior as you would in another language that supports optional arguments.
Here’s one example using the Documents.Add method. If you look at this using the Object Browser in C# you won’t get much help in determine what values to provide for the optional arguments, since in C# they aren’t optional.
If you have Visual Studio, the Visual Basic Object Browser is a good way to determine what the expected input is. The Documents.Add method is shown below and its signature appears at the bottom of the browser. The first argument specifying the document type doesn’t have a default value and must always be supplied. The second argument specifying the template is optional, and defaults to an empty String. The third value is also optional Boolean and defaults to True.
Here are examples of VBA and C# code calling the Documents.Add method where the desire is to take the default values for the optional arguments.
VBA
Set doc = ThisApplication.Documents.Add(kPartDocumentObject)
C#
doc = invApp.Documents.Add(DocumentTypeEnum.kPartDocumentObject,
"", true);
The other case you’ll run into are arguments where the default value in Visual Basic is Nothing. This is demonstrated in the AssemblyConstraints.AddMate method where the last two arguments default to Nothing, as shown below.
In C#, instead of Nothing you can use Type.Missing, as shown in the code below.
mate = asmDef.Constraints.AddMateConstraint(face1, face2, 0,
InferredTypeEnum.kNoInference,
InferredTypeEnum.kNoInference,
Type.Missing, Type.Missing);
Casting
When making variable assignments, VBA and Visual Basic will automatically cast from one type to another when it’s possible. C# doesn’t do this automatically so you have to explicitly cast variables. Here’s some VBA code demonstrating the complete sample from above that places a mate constraint.
Public Sub AddMate()
Dim asmDoc As AssemblyDocument
Set asmDoc = ThisApplication.ActiveDocument
Dim asmDef As AssemblyComponentDefinition
Set asmDef = asmDoc.ComponentDefinition
Dim face1 As face
Set face1 = ThisApplication.CommandManager.Pick( _
SelectionFilterEnum.kPartFacePlanarFilter, _
"Select planar face 1.")
Dim face2 As face
Set face2 = ThisApplication.CommandManager.Pick( _
SelectionFilterEnum.kPartFacePlanarFilter, _
"Select planar face 2.")
Dim mate As MateConstraint
Set mate = asmDef.Constraints.AddMateConstraint(face1, face2, 0)
End Sub
Here’s the equivalent code in C#. There are several casts required to get this code to work. The casts are needed because those calls are typed to return a value different than the variable it’s being assigned to. For example, the Application.ActiveDocument property is typed to return an object of type Document and it’s being assigned to a variable typed as AssemblyDocument. Visual Basic and VBA handle this conversion automatically. In C# you need to tell it the conversion type by adding the (AssemblyDocument) cast. The same thing is required with the Pick method which is typed to return an Object.
AssemblyDocument asmDoc = (AssemblyDocument)invApp.ActiveDocument;
AssemblyComponentDefinition asmDef = asmDoc.ComponentDefinition;
Face face1 = (Face)invApp.CommandManager.Pick(
SelectionFilterEnum.kPartFacePlanarFilter,
"Select planar face 1.");
Face face2 = (Face)invApp.CommandManager.Pick(
SelectionFilterEnum.kPartFacePlanarFilter,
"Select planar face 2.");
MateConstraint mate;
mate = asmDef.Constraints.AddMateConstraint(face1, face2, 0,
InferredTypeEnum.kNoInference,
InferredTypeEnum.kNoInference,
Type.Missing, Type.Missing);
Casting problems are typically easy to catch because the error from Visual Studio tells you exactly what the problem is.
Here’s another example that isn’t specifically a casting issue but is somewhat related and the easy way to solve the problem is by using casting. Below is some VBA code that gets the first body in the active part document. (Remember that a
“ _” (space underscore) identifies a line continuation in Visual Basic.)
Set body = ThisApplication.ActiveDocument. _
ComponentDefinition.SurfaceBodies.Item(1)
Here’s the same code converted to C#.
SurfaceBody body;
body = invApp.ActiveDocument.ComponentDefinition.SurfaceBodies[1];
The above code doesn’t work in C# and results in the error shown below. This is because the ActiveDocument property returns a Document object, not a PartDocument object, and the Document object does not support the ComponentDefinition property.
Breaking the line up to first get the PartDocument object, which requires casting, and then using that object to get the body fixes the problem.
PartDocument partDoc = (PartDocument) invApp.ActiveDocument;
SurfaceBody body = partDoc.ComponentDefinition.SurfaceBodies[1];
Declaring Arrays
When you declare an array in VBA it is automatically initialized. In C# (and VB.Net) declaring an array does not initialize it. You need to add a bit more to the declaration to cause the initialization. If you don’t initialize the array you’ll get an error when you pass the array as a method argument.
VBA
VB.Net
C#
Resizing an Array
In VB/VBA you can resize an array and maintain its current contents by using the Redim statement using the Preserve option. C# can’t dynamically resize an array so to accomplish the equivalent you create a new array of the desired size and copy the original array into it.
VBA
newSize = 500
Redim Preserve stuff(newSize)
C#