Using Linq in C++/CLI January 6, 2010 Yes, it is possible to use all the Linq functionality in mixed-mode C++/CLI assemblies or executables. The main issue is to work around a bug which causes the Visual Studio 2008 C++ compiler to crash when it sees both core.dll (LINQ) and managed String operations at the same time. Here is the error you might see:
fatal error C1001: An internal error has occurred in the compiler.
(compiler file 'f:\dd\vctools\compiler\utc\src\p2\main.c[0x5110E0DB:0x00000030]', line 182)
To work around this problem, try simplifying or changing the program near the locations listed above.
I assume that this will be fixed in VS 2010, set to release three months from now. In the meantime, as a workaround, you can create wrappers for most of the managed String functions as shown below.

It's also a bit cumbersome to pass functions to the Linq extension methods, since you don't have access to the C# 3.5 lambda sugar. But this too is possible as shown in the example code.

We do not add core.dll to the project references because we don't want MyStringFix.cpp (see below) to use it. Instead, we import it directly in the following header file, which is included in every other source file in your project.
// This is the .h file included by all of your source files except MyStringFix.cpp
#define UNICODE
#include "windows.h"
#include "commctrl.h"
#include "shlwapi.h"
#include <vcclr.h>
#include <wchar.h>

#pragma managed

using namespace System;
using namespace System::IO;
using namespace System::Drawing;
using namespace System::Diagnostics;
using namespace System::Text;
using namespace System::Collections;
using namespace System::Collections::Generic;
using namespace System::Runtime::InteropServices;
#using <C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll>

// Bug fix wrapper methods for String operations
String^ __clrcall MyStringFormat(String^ s, ... array<Object^>^);
String^ __clrcall MyStringAppend(String^ s, String^ s1);
String^ __clrcall MyStringAppendFormat(String^ s, String^ fmt, ... array<Object^>^ rg);
String^ __clrcall MyNewString(char *p,int idx,int cch, Encoding^ enc);
String^ __clrcall MyNewString(char *p);
String^ __clrcall MyNewString(unsigned char *p);
String^ __clrcall MyNewString(wchar_t *p);
String^ __clrcall MyNewString(wchar_t *p,int cch);
int __clrcall MyStringLen(String^ s);
bool __clrcall MyStringIsEmpty(String^ s);
String^ __clrcall MyStringReplace(String^ s,String^ txt,String^ repl);
bool __clrcall MyStringIsNullOrEmpty(String ^s);
String^ __clrcall MyStringTrim(String ^s);
String^ __clrcall MyStringIntern(String^ s);
String^ __clrcall MyStringJoin(String^ sep, array<String^>^ rg);
bool __clrcall MyStringEqual(String^ s1,String^ s2);

// ... etc.
Now that core.dll is referenced by all of your project's source files, we must make sure that they use the following wrapper functions for all managed String operations, rather than doing them directly inline. Notice that the following file does not include any .h files, and thus does not reference core.dll.
// MyStringFix.cpp
using namespace System;
using namespace System::Text;

int MyStringLen(String^ s) { return s->Length; }
String^ MyStringFormat(String^ s, ... array<Object^>^ rg) { return String::Format(s,rg); }
String^ MyStringAppend(String^ s, String^ s1) { return s + s1; }
String^ MyStringAppendFormat(String^ s, String^ fmt, ... array<Object^>^ rg) { return s + String::Format(fmt,rg); }
String^ MyNewString(char *p,int idx,int cch, Encoding^ enc) { return gcnew String(p,idx,cch,enc); }
String^ MyNewString(char *p) { return gcnew String(p); }
String^ MyNewString(unsigned char *p) { return gcnew String((char *)p); }
String^ MyNewString(wchar_t *p) { return gcnew String(p); }
String^ MyNewString(wchar_t *p,int cch) { return gcnew String(p,0,cch); }
bool MyStringIsEmpty(String^ s) { return s == String::Empty; }
bool MyStringIsNullOrEmpty(String ^s) { return String::IsNullOrEmpty(s); }
String^ MyStringReplace(String^ s,String^ txt,String^ repl) { return s->Replace(txt,repl); }
String^ __clrcall MyStringTrim(String ^s) { return s->Trim(); }
String^ __clrcall MyStringIntern(String^ s) { return String::Intern(s); }
String^ __clrcall MyStringJoin(String^ sep, array<String^>^ rg) { return String::Join(sep, rg); }
bool __clrcall MyStringEqual(String^ s1,String^ s2) { return s1==s2; }
Now you're ready to do Linq operations in any of your source files:
// ...

for each (String^ s in Linq::Enumerable::ToArray(Linq::Enumerable::Except(l,pm->Keywords)))
	pm->AddKeyword(s);

// ...

Category^ gk = Linq::Enumerable::FirstOrDefault(mkat->ImmediateParents);

// ...

if (Linq::Enumerable::Any(def->ClassifierUsage))
{
	MessageBox(hWnd, /* etc */ ,MB_OK);
	break;
}

// ...

List<unsigned>^ l = pg->GetMultiSel();
l->Sort();
l = Linq::Enumerable::ToList(Linq::Enumerable::Reverse(l));

// ...
As for using predicates and other lambdas, it is a bit cumbersome, as I mentioned above. However, the following does work just fine.

// demo object class
ref class MyObject
{
public:
	unsigned id;
}

// predicate class contains information relevant to the current search, plus the predicate
// evaluation function
ref class FilterByIdPredicateClass
{
	unsigned srch_id;
public:
	pred_dopbase_filter_id(unsigned srch)
	{
		srch_id = srch;
	}

	bool __clrcall func(MyObject^ dopb)
	{
		return dopb->Id == srch_id;
	};
};

// ...

// some demo objects
array<MyObject^>^ rg = gcnew array<MyObject^>(5);
rg[0] = gcnew MyObject(5);
rg[1] = gcnew MyObject(999);
rg[2] = gcnew MyObject(7);
rg[3] = gcnew MyObject(1234);
rg[4] = gcnew MyObject(3);

// create a predicate instance for the desired operation. '1234' is the value we will search for.
FilterByIdPredicateClass^ filter_instance = gcnew FilterByIdPredicateClass(1234);
Func<MyObject^,bool>^ pred = gcnew Func<MyObject^,bool>(filter_instance,&FilterByIdPredicateClass::func);

// retrieve object according to the predicate
MyObject^ o = Linq::Enumerable::FirstOrDefault<MyObject^>(rg, pred);