Improved COM Interoperability in .NET 4.0

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Improved COM Interoperability Introduction


Welcome to this installment of the .NET Nuts & Bolts column. The prior article focused on the future direction of managed languages and introduced trends that are influencing the future of C# and Visual Basic. It introduced the Dynamic Language Runtime (DLR) and touched ever so briefly on the improved COM interoperability that is coming along with that. This article will build on that and provide specifics.


Optional and Named Parameters


Traditionally C# has avoided the implementation of optional and named parameters. The thought process being that overloading could provide much of what was necessary. The following example demonstrates sample method footprints for a method to open a text file and several overloads for it.


  public StreamReader OpenTextFile(
string path,
Encoding encoding,
bool detectEncoding,
int bufferSize);

public StreamReader OpenTextFile(
string path,
Encoding encoding,
bool detectEncoding);

public StreamReader OpenTextFile(
string path,
Encoding encoding);

public StreamReader OpenTextFile(string path);



However, with the commitment to co-evolution between C# and Visual Basic it is necessary for C# to join with the ranks of VB and support optional and named parameters. The revised example using optional parameters is below. This creates the ability to vary the method calls with only a single definition.


  // With optional parameters
public StreamReader OpenTextFile(
string path,
Encoding encoding = null,
bool detectEncoding = true,
int bufferSize = 1024);

// Method call excluding the last two parameters
OpenTextFile(“foo.txt”, Encoding.UTF8);



In order to allow for any and all parameters to be optional, the concept of named parameters goes hand-in-hand.




  • Named arguments can appear in any order as long as all names are given
  • Named arguments must be last in the list of parameters if not all parameters are named
  • Arguments are evaluated in the order given
  • Non-optional parameters must always be specified


  // Uses a named argument in last position
OpenTextFile(“foo.txt”, Encoding.UTF8, bufferSize: 4096);

// Uses named parameters to reorder the parameters and leave one out
OpenTextFile(
bufferSize: 4096,
path: “foo.txt”,
detectEncoding: false);



Optional and named parameters have a direct benefit to COM Interoperability. The following example represents code that would previously have been required to create and save a Word document.


  object fileName = “Test.docx”;
object missing = System.Reflection.Missing.Value;
doc.SaveAs(ref fileName,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing);


With optional and named parameters, the above example can be heavily simplified to the simple code below, which results in Office automation and other code finally looking the way it was intended to look.


  doc.SaveAs(“Test.docx”);


Automatic Object to Dynamic Mapping


The Dynamic Language Runtime (DLR) introduces the concept of object binders. By default the DLR includes a COM binder that maps dynamic types to statically typed .NET objects. The following sample code shows a snippet of code that is part of reading all of the processes on the local machine and then graphing resources in Excel. Note the heavy use of casting within the code and how it makes the code much more complicated to read.


  xl.Workbooks.Add(Type.Missing);
xl.Visible = true;

((Excel.Range)xl.Cells[1, 1]).Value2 = “Process Name”;
((Excel.Range)xl.Cells[1, 2]).Value2 = “Memory Usage”;

int i = 2;
foreach (var proc in (from p in Process.GetProcesses()
orderby p.VirtualMemorySize64 descending
select p).Take(20))
{
((Excel.Range)xl.Cells[i, 1]).Value2 = proc.ProcessName;
((Excel.Range)xl.Cells[i, 2]).Value2 = proc.VirtualMemorySize64;
i++;
}

Excel.Range cellRange = (Excel.Range)xl.Cells[1, 1];

Excel.Chart xlChart = (Excel.Chart)xl.ActiveWorkbook.Charts.
Add(Type.Missing, xl.ActiveSheet, Type.Missing, Type.Missing);



The following code has been revised to rely on the object binder to do the mapping:


  //Optional parameters
xl.Workbooks.Add();
xl.Visible = true;

//Automatic conversion into dynamic
xl.Cells[1, 1].Value2 = “Process Name”;
xl.Cells[1, 2].Value2 = “Memory Usage”;

int i = 2;
foreach (var proc in (from p in Process.GetProcesses()
orderby p.VirtualMemorySize64 descending
select p).Take(20))
{
//Automatic conversion into dynamic
xl.Cells[i, 1].Value2 = proc.ProcessName;
xl.Cells[i, 2].Value2 = proc.VirtualMemorySize64;
i++;
}

//Equality Conversion
Excel.Range cellRange = xl.Cells[1, 1];

//Equality Conversion + Named Parameters + Optional Parameters
Excel.Chart xlChart = xl.ActiveWorkbook.Charts.Add(After:xl.ActiveSheet);



Optional “ref” Modifier


With the next release of the .NET Framework you will be able to omit the “ref” keyword in some cases when talking to COM.


Interop Type Embedding (“No PIA”)


Another feature being introduced that will yield COM Interoperability improvements has to do with not requiring the primary interop assembly (PIA). Traditionally there would have been a number of additional DLLs you would have had to deploy with your application to support specialized types. These types can be embedded directly in to the application now, which means you don’t need the primary assembly at all to utilize these types.


Summary


You have now seen some of the COM interoperability improvements that are coming along with the DLR such as optional and named parameters. The introduction of this functionality should make COM Interop code not only easier to write, but also to read and maintain in the long run.


Future Columns


The topic of the next column is likely to be more on the benefits coming with .NET Framework 4.0. If you have something else in particular that you would like to see explained here you could reach me at mark.strawmyer@crowehorwath.com.

More by Author

Previous article
Next article

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read