tags:

views:

189

answers:

4

I have been keeping up with .NET CLR for awhile now, and my language of choice is C#.

Up until recently, I was unaware that C++/CLI could produce "mixed mode" executables capable of running native and managed code.

Now knowing this, another developer friend of mine were discussing this attribute and trying to determine when and how this ability would be useful.

I take it as a given that native code has the capability to be more efficient and powerful than managed code, at the expense of additional development time.

In the past, I resorted to strictly native C++ code libraries and used Interop to make use of the functionality I wrote into the native library.

I can see the benefit of not requiring an additional library, but I'm curious as to what all the pros/cons of using C++/CLI over soley managed executable created in C#, or such an executable using Interop to call a purely native C++ library?

(Sidenote: Are the terms Interop/PInvoke interchangeable, as I d.on't understand the difference between the terms, simply seen them used the same way.)

+9  A: 

With C++/CLI you can create, broadly speaking, three types of objects:

  1. Managed types. These will compile down to essentially the same IL as the equivalent C#. There is no performance opportunity here.
  2. Native types. Compiles down to native code as if you'd used straight C++.
  3. Mixed mode types. These compile down to managed code, but allow you to refer to native types too.

You might think of (3) as being like writing C# code with PInvoke code to accessing the native stuff - except all the PInvoke stuff is generated for you.

There's more to it than that, of course, as well as some caveats - but that should give you an idea of how it's useful.

In other words it's really a glue language. While you can write fully fledged apps in C++/CLI it's more normal to keep the managed and native parts separate and use C++/CLI to bridge the two more cleanly than with PInvoke.

Another common use is to extend and existing, native, C++ code base with .Net library calls.

Just be careful that you partition your code well as it can be quite subtle sometimes in compiling your pure C++ code down to IL transparently!

As to your sidenote: PInvoke is a particular type of Interop. Interop comes in other forms too, such as COM Interop. In fact, more accurately, PInvoke is a set of language features that make Interop with native code easier.

Phil Nash
+1 for calling it a glue language. Best description of C++/CLI yet.
Randolpho
yes, and the fumes can be equally toxic ;-)
Phil Nash
Oh, I dunno about that. I rather enjoy it, actually.
Randolpho
- as do some people enjoy the fumes from glue
Phil Nash
caveat - I'm working on some particularly twisted C++/CLI wrappers at the moment
Phil Nash
Keep in mind that if you ever intend to port a wrapper to Mono, you can't use C++/CLI unless it's completely managed. Mono doesn't support unmanaged code in C++/CLI. That's why I always stick to P/Invoke if I can.
David Brown
Good point David, especially outside out Enterprise software. You should probably have posted that as a response of your own
Phil Nash
Thanks Phil, that explanation really helps!
Aequitarum Custos
I always thought C++/CLI was a way of getting c++ programmers to use .Net because they didn't have to learn much new stuff, just learn the ^ and gcnew and your done yeah?
Spence
+1  A: 

I've used Managed C++ (the .NET 1.1 precursor to C++/CLI) effectively in the past. I find it works best when you have a native C or C++ library you wish to use in managed code. You could go the whole Interop/PInvoke route, which makes for some ugly C# code and frequently has marshalling issues, or you could write a managed C++ wrapper, which is where C++/CLI really shines.

Because C++/CLI is managed code, you can call it from C# (or VB.NET if you lean that way) in the normal way, by adding a reference to the .DLL. No marshalling, no dllimport, nothing goofy like that. Just normal project references. Additionally, you get the benefit of static linked libraries if your native library is so designed, which is a Good Thing (tm).

Randolpho
+2  A: 

Phil Nash really hit the big things. Here's one more that I've hit more than once and is the primary reason I've used C++/CLI in the past:

Some applications are extended by checked all DLLs in some location for exported functions with a particular name. In C#, there's no way to declare a native C-style export, but you can in C++/CLI. I create a "wrapper" in C++/CLI that exports the method, handles any translation of C structs to managed objects and passes the call on to an assembly written in C#.

280Z28
That is a very interesting idea, never thought of that.
Aequitarum Custos
A: 

There are certain types that are not available to other languages, such as templates, const and tracking handle of boxed value types.

templates are specialized at compile-time. generics are specialized at runtime. Although CLR should cache generics specialization for future use (so you get the same List each time you use it), there is still a performance hit each time a generics specialization is requested.

i know other languages discard the const attribute, but have compile time checking in your C++ code is better than nothing.

Having a type like int^ allows you to access the memory on the managed heap directory without unnecessary unboxing. This can help performance when passing tracking handles of boxed values to functions that expect a tracking handle, such as Console::WriteLine(Object^). Of course the early boxing initialization can not be avoided. In other languages you can store the reference in an Object variable and pass it around to avoid unboxing, but you lose the compile time type check.

Sheng Jiang 蒋晟
Generics are not templates. There will be a performance hit the first time you access an reference typed version of the generic. Once done though it will reuse the same reference type generic for all types which will not invoke the compiler. Clearly though if you have a precompiled type for a given object via templates then that will be faster.
Spence
The reusing is done by checking the generic type cache. The checking is not free.
Sheng Jiang 蒋晟