Cross-language Extension Method Calling

Extension methods are a concise way of binding functions to particular types.

In my last post, I showed how Extension methods can be created in the .NET 2.0 environment.
In this post, I discuss calling the extensions from other languages.

Most of the differences I find between the Dot Net languages are mainly syntax.  The declaration of Extensions is no exception.  There is, however, a distinct difference with the framework accepting excensions made with C++ that differs from C# and VB. 

When calling the C++ extension from C#, the compiler will SOMETIMES say there is no definition for DoCPP with the error:
'string' does not contain a definition for 'DoCPP' and no extension method 'DoCPP' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?)

If I recompile, the error goes away.

The strangest problem with calling the C++ extension from C# is that I first must make SOME type of reference to the class BEFORE using the extension or it will not be recognized at all.  So, if I first call the DoCPP() as a static method, the extension works fine later.  If I make a dummy instantiation of the class, it works.  If I have no forward reference of the class, I get the same error as before and recompiling does not fix it.  It seems as if this none of this is supposed to work across the languages.

I have made a few work-arounds to get the examples to compile and run.

Note the following examples:


Extension in C#

using System;

namespace Extension_CS
{
   public static class CExtension_CS
   {  //in C#, the "this" keyword is the key.
      public static void DoCS(this string str)
      {
         Console.WriteLine("CS\t{0:G}\tCS", str);
      }
   }
}



Extension in C++

/****************************************************************************\
 * Here is the C++ implementation.  It is the least elegant and most quirky,
 * but it works.
\****************************************************************************/
#pragma once
using
namespace System;
using namespace System::Runtime::CompilerServices;     //<-Essential
// Reference: System.Core.dll //<- Essential

namespace Extension_CPP {
       public ref class CExtension_CPP
       {
       public:
              [Extension] // or [ExtensionAttribute] /* either works */
              static void DoCPP(String^ str)
              {
                     Console::WriteLine("C++\t{0:G}\tC++", str);
              }
       };
}


Extension in VB

 

 


Calling program in C#

/******************************************************************************\
 * Main calling program
 * Intellisense and VS2008 complain about the CPP implementation, but with a
 * little duct-tape, it works just fine.
\******************************************************************************/
using System;
using Extension_CPP;
using Extension_CS;
using Extension_VB; // virtual namespace

namespace TestExtensions
{
   public static class CTestExtensions
   {
      /**********************************************************************\
       * For some reason, this needs a direct reference into the C++ version
       * even though it does nothing than add a null reference.
       * The constructor provides the fake usage to please the compiler.
      \**********************************************************************/
      private static CExtension_CPP x = null;   // <-DUCT_TAPE!
      static CTestExtensions()
      {
         // Fake usage to stop compiler from complaining
         if (null != x) {} // <-DUCT_TAPE
      }

      static void Main(string[] args)
      {
         string strData = "from C#";
         strData.DoCPP();
         strData.DoCS();
         strData.DoVB();
      }
   }
}

 


Calling program in VB 

 


 Calling program in C++

 

 

// TestExtensions_CPP.cpp : main project file.

#include "stdafx.h"

using namespace System;
using namespace Extension_CPP;
using namespace Extension_CS;
using namespace Extension_VB;

void main(void)
{
      
/*******************************************************\
        * Extension methods are called like static methods
        * when called from C++.  There may be a difference in
        * syntax when calling the VB extension as VB Extensions
        * are embedded in Modules instead of classes
       \*******************************************************/
    String^ strData = "from C++";
    CExtension_CPP::DoCPP(strData);
    CExtension_CS::DoCS(strData);
    modExtension_VB::DoVB(strData);
//since Extensions go in Modules
}



 

Imports Extension_CPP
Imports Extension_CS
Imports Extension_VB
Imports System.Runtime.CompilerServices

Module TestExtensions_VB
   <Extension()> _
     
Public Sub DoCPP(ByVal str As String)
     
'Framework does not treat this as an extension, so use the static
      CExtension_CPP.DoCPP(str)
  
End Sub

   Sub Main()
     
Dim strData As String = "from VB"
      strData.DoCS()
      strData.DoVB()
      strData.DoCPP()
'fake
   End Sub
End
Module


' Here is the VB implementation.  This is not as elegant as the C#, but it's
' functional.
Imports System.Runtime.CompilerServices
'
Public Module modExtension_VB 'Extension methods can be defined only in modules.
   <Extension()> _
      Public Sub DoVB(ByVal str As String)
      Console.WriteLine("VB" & Chr(9) & "{0:G}" & Chr(9) & "VB", str)
   End Sub
End
Module

posted @ Friday, March 5, 2010 5:22 PM
Print

Comments on this entry:

# re: Cross-language Extension Method Calling

Left by James Gwinnutt at 4/26/2010 4:09 AM
Gravatar
Hi Tom,

Please could you clarify what the line below (in 'calling program in c#') does:

using Extension_VB; // vitual namespace

It appears to just give a 'undefined' compile-time error.

I'm trying to call a VB extension method from C#... it works fine if i invoke it using static method syntax, i.e.

Module.Function(object, various parameters..)

but for some reason the c# compiler doesn't like invoking it using extension method syntax:

Object.Function(various parameters)

... yet this syntax can be used fine in VB!

Thanks for any help you can give.

# re: Cross-language Extension Method Calling

Left by Tom at 4/26/2010 9:10 AM
Gravatar
James, good question!
I do not have Extension_VB set up as an actual namespace, but I've assumed because the AssemblyInfo.vb has the AssemblyTitle and/or the AssemblyProduct set to Extension_VB, then the framework somehow treats it as a namespace.

This has worked in both VS2008 Standard and VS2010 RC.

[AssemblyInvo.vb]
<Assembly: AssemblyTitle("Extension_VB")>
<Assembly: AssemblyProduct("Extension_VB")>

Your comment:



(not displayed)

 
 
 
 
 

Live Comment Preview:

 
«July»
SunMonTueWedThuFriSat
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789