C++/CLI Enumerable::GroupJoin example for MSDN

Adding to the “Missing from MSDN” series of posts:

I find tremendous benefit in the Enumerable::GroupJoin method for mimicking the function of a left outer join in SQL --
the construct where the system reports back to you all “keys” and “values” even if the values (results) are null or empty.

With the regular Enumerable::Join, only the Key-Value pairs or groupings are returned when there is an associated result.
I had found a nifty way of inverting the join to retrieve non-matching results and it was of use until I discovered Enumerable::GroupJoin.

For all of my uses of Enumerable.* in C++/CLI, I always create a helper class to hold methods and the Funcs that will be used as delegates.
This helps prevent clutter and allows for easier reuse.

Keeping with the tradition of creating an examples that COULD HAVE BEEN in MSDN, please examine the code below.
I took the liberty of using IEnumerable<String^>^ instead of List<String^>^ to remove unnecessary code (well, sort of…).
I also chose to not give Magnus Hedland a pet, so the alternate benefit could be shown (a record with no result).

 
#include "stdafx.h"
using namespace System;
using namespace System::Collections::Generic;
using namespace System::Linq;
public ref class Person
{
public:
   property String^ Name;
   Person(String^ Name) { this->Name = Name; }
};
public ref class Pet
{
public:
   property String^ Name;
   property Person^ Owner;
   Pet(String^ Name, Person^ Owner) { this->Name = Name; this->Owner = Owner; }
};
public ref class CPersonPetHelper
//http://www.GeeksWithBlogs.Net/THines01
private:
   static String^ GetNameFromPerson(Person^ person) { return person->Name; }
   static String^ GetNameFromPetOwner(Pet^ pet) { return pet->Owner->Name; }
   static String^ GetPetName(Pet^ pet) { return pet->Name; }
   static Func<Pet^, String^>^ getPetName = gcnew Func<Pet^, String^>(GetPetName);
   //
   static KeyValuePair<String^, IEnumerable<String^>^> GetKvpFromOwnerAndPets(Person^ owner, IEnumerable<Pet^>^ pets)
   {
      return KeyValuePair<String^, IEnumerable<String^>^>
      (
         owner->Name,
         Enumerable::Select<Pet^, String^>(pets, getPetName)
      );
   }
   //
   static String^ GetStrFromKvpS2L2s(KeyValuePair<String^, IEnumerable<String^>^> kvp_s2L2s)
   {
      return String::Join("\n  ",
         Enumerable::Concat<String^>(
         (gcnew  array < String^ > { kvp_s2L2s.Key + ":" }), kvp_s2L2s.Value));
   }
public:
   static Func<Person^, String^>^ getNameFromPerson = gcnew Func<Person^, String^>(GetNameFromPerson);
static Func<Pet^, String^>^ getNameFromPetOwner = gcnew Func<Pet^, String^>(GetNameFromPetOwner);
static Func<Person^, IEnumerable<Pet^>^, KeyValuePair<String^, IEnumerable<String^>^>>^ getKvpFromOwnerAndPets =
      gcnew Func<Person^, IEnumerable<Pet^>^, KeyValuePair<String^, IEnumerable<String^>^>>(GetKvpFromOwnerAndPets);
static Func<KeyValuePair<String^, IEnumerable<String^>^>, String^>^ getStrFromKvpS2L2s =
      gcnew Func<KeyValuePair<String^, IEnumerable<String^>^>, String^>(GetStrFromKvpS2L2s);
};
static void GroupJoinEx()
//http://www.GeeksWithBlogs.Net/THines01
   array<Person^, 1>^ people =
   {
      gcnew Person("Hedlund, Magnus"),
      gcnew Person("Adams, Terry"),
      gcnew Person("Weiss, Charlotte")
   };

   array<Pet^, 1>^ pets =
   {
      gcnew Pet("Barley", people[1]),
      gcnew Pet("Boots", people[1]),
      gcnew Pet("Whiskers", people[2]),
      gcnew Pet("Daisy", people[1])
   };

   array<KeyValuePair<String^, IEnumerable<String^>^ >, 1>^ kvp_s2L2s =
      Enumerable::ToArray<KeyValuePair<String^, IEnumerable<String^>^>>
      (
         Enumerable::GroupJoin<Person^, Pet^, String^, KeyValuePair<String^, IEnumerable<String^>^>>
         (
            people,
            pets,
            CPersonPetHelper::getNameFromPerson,
            CPersonPetHelper::getNameFromPetOwner,
            CPersonPetHelper::getKvpFromOwnerAndPets
         )
      );

   Console::WriteLine
   (
      String::Join("\n",
         Enumerable::Select < KeyValuePair<String^, IEnumerable<String^>^>, String^ >
         (
            kvp_s2L2s,
            CPersonPetHelper::getStrFromKvpS2L2s
         ))
   );
}

C++/CLI Shell Exercise Code

A number of years ago, I was helping someone on DaniWeb with some code that was (probably) more than they expected.
I never got closure on the code because it seemed the requester didn’t understand to use Visual Studio.
ANYWAY:
I recently revisited that code and realized how differently I would have done things if I created it today.
It’s like that old cartoon from NotInventedHere.com on 4/20/2010 where one character can’t stand to see his old code:

 

Well, I had the same reaction to mine (as I frequently do) and so I rewrote portions of it.
Luckily, it was short and I knew SPECIFICALLY what I wanted done (for now).

I figured I’d go ahead and post it for future reference (when I once again can’t stand it).

This code puts into practice multiple techniques for using Linq and IEnumerable in C++/CLI.
The program itself is a simple shell-program where the user has a command-line and can enter
some simple commands.

This was probably someone’s homework, but the implementation I demonstrated might not have been
something he/she could have turned in.  LOL.

// DW_393014.cpp : main project file.
#include "stdafx.h"
using namespace System;
using namespace System::Collections::Generic;
using namespace System::IO;
using namespace System::Linq;
 
public ref class CCommands
{
private:
	//
	static void _doShowDir(void)
	{
		Console::WriteLine(
			String::Join("\r\n",
				Enumerable::ToArray<String^>(
					Directory::GetFiles(
						Directory::GetCurrentDirectory()))));
	}
	//
	static void _doHelp()
	{
		Console::WriteLine("Commands are: " +
			String::Join(", ",
				Enumerable::ToArray<String^>(
					Enumerable::Select(arr_kvp_s2aCommands, getKeyFromKvpS2a))) + ", quit, exit");
	}
	//
	static Action^ _getActFromKvpS2aJoin(KeyValuePair<String^, Action^> kvpS2a, String^) { return kvpS2a.Value; }
	//
	static Action^ _clear = gcnew Action(Console::Clear);
	static Action^ _help = gcnew Action(_doHelp);
	static Action^ _showDir = gcnew Action(_doShowDir);
	//
	static String^ _getKeyFromKvpS2a(KeyValuePair<String^, Action^> kvp_s2a) { return kvp_s2a.Key; }
	static String^ _getStringAsString(String^ str) { return str; }
	//
	static bool _notNothing(Action^ act) { return nullptr != act; }
	static void _doNothing(){}
public:
	static Func<KeyValuePair<String^, Action^>, String^>^ getKeyFromKvpS2a =
		gcnew Func<KeyValuePair<String^, Action^>, String^>(_getKeyFromKvpS2a);
 
	static Func<String^, String^>^ getStringAsString = gcnew Func<String^, String^>(_getStringAsString);
 
	static Func<KeyValuePair<String^, Action^>, String^, Action^>^ getActFromKvpS2aJoin =
		gcnew Func<KeyValuePair<String^, Action^>, String^, Action^>(_getActFromKvpS2aJoin);
 
	static String^ NowTime(DateTime^ dt)
	{
		return String::Format("{0}:{1}:{2}",
			dt->Hour.ToString("D2"),
			dt->Minute.ToString("D2"),
			dt->Second.ToString("D2"));
	}
 
	//
	static IEnumerable<KeyValuePair<String^, Action^>>^ arr_kvp_s2aCommands =
		gcnew array<KeyValuePair<String^, Action^>>
		{
			KeyValuePair<String^, Action^>("spy", _showDir),
			KeyValuePair<String^, Action^>("wipe", _clear),
			KeyValuePair<String^, Action^>("help", _help),
		};
 
	static Action^ DoNothing = gcnew Action(_doNothing);
	static Func<Action^, bool>^ IsSomething = gcnew Func<Action^, bool>(_notNothing);
};
 
int main(void)
{	//array<System::String ^> ^args)
	Console::WriteLine(L"Welcome to CLI Shell (v1.0)\n");
 
	array<String^>^ arr_strQuitExit = { "exit", "quit" };
	String^ strCommand = "";
 
	while (!Enumerable::Contains<String^>(arr_strQuitExit, strCommand))
	{
		Console::Write("{0}>: ", CCommands::NowTime(DateTime::Now));
		strCommand = Console::ReadLine()->ToLower();
 
		//////////////////////////////////////////////////////////////////////////////
		// Invoke the first non-null Action that matches the command
		// If no match, call the DoNothing action.
		Enumerable::First<Action^>
		(	// construct pieces ensures no nulls
			gcnew array <Action^>
			{	// [0]=desired command, [1]=fall-back
				Enumerable::FirstOrDefault<Action^>
				( // returns nullptr if no matching command
					Enumerable::Join<KeyValuePair<String^, Action^>, String^, String^, Action^>
					(
						CCommands::arr_kvp_s2aCommands,
						gcnew array <String^> { strCommand }, // array of 1
						CCommands::getKeyFromKvpS2a,		// get the Key (string)
						CCommands::getStringAsString,    // return the string
						CCommands::getActFromKvpS2aJoin  // (KVP, STR) => KVP->Key
					)
				),
				CCommands::DoNothing // when no match or nullptr
			},
			CCommands::IsSomething // not nullptr
		)->Invoke();
	}
	//
	return 0;
}

Enumerable::SelectMany Example in C++/CLI for MSDN

Here is another example taken (slightly) directly from the MSDN page concerning Enumerable::SelectMany.
This example is in C++/CLI and appears to be missing from the list of examples.

// MSDN_bb534336_CPP.cpp : main project file.
// https://msdn.microsoft.com/en-us/library/vstudio/bb534336(v=vs.100).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2
#include "stdafx.h"
using namespace System;
using namespace System::Collections::Generic;
using namespace System::Linq;
 
public ref class PetOwner
{
private:
	static List<String^>^ GetPets(PetOwner^ petOwner) { return petOwner->Pets;	}
	static IEnumerable<String^>^ GetListAsArray(List<String^>^ lst) { return lst; }
	static IEnumerable<String^>^ GetArrayAsArray(IEnumerable<String^>^ arr) { return arr; }
 
public:
	property String^ Name;
	property List<String^>^ Pets;
 
	PetOwner(String^ Name, List<String^>^ Pets)
	{
		this->Name = Name;
		this->Pets = Pets;
	}
 
	static Func<PetOwner^, List<String^>^>^ getPets = gcnew Func<PetOwner^, List<String^>^>(GetPets);
	static Func<List<String^>^, IEnumerable<String^>^>^ getListAsArray = gcnew Func<List<String^>^, IEnumerable<String^>^>(GetListAsArray);
	static Func<IEnumerable<String^>^, IEnumerable<String^>^>^ getArrayAsArray = gcnew Func<IEnumerable<String^>^, IEnumerable<String^>^>(GetArrayAsArray);
};
 
static void SelectManyEx1()
{
	array<PetOwner^, 1>^ petOwners =
	{
		gcnew PetOwner("Higa, Sidney", Enumerable::ToList<String^>(gcnew array < String^, 1 > { "Scruffy", "Sam" })),
		gcnew PetOwner("Ashkenazi, Ronen", Enumerable::ToList<String^>(gcnew array < String^, 1 > { "Walker", "Sugar" })),
		gcnew PetOwner("Price, Vernette", Enumerable::ToList<String^>(gcnew array < String^, 1 > { "Scratches", "Diesel" }))
	};
 
	// Query using SelectMany().
	IEnumerable<List<String^>^>^ query3 =
		Enumerable::Select<PetOwner^, List<String^>^>
		(	// extract List of String^ from PetOwners
			petOwners, PetOwner::getPets
		);
 
	// This code shows how to use Select() 
	// instead of SelectMany().
 
	Console::WriteLine("\nUsing Select():");
	// Notice that two foreach loops are required to 
	// iterate through the results
	// because the query returns a collection of arrays.
	for each(List<String^>^ petList in query3)
	{
		for each(String^ pet in petList)
		{
			Console::WriteLine(pet);
		}
 
		Console::WriteLine();
	}
 
	IEnumerable<IEnumerable<String^>^>^ query2 =
		Enumerable::Select<List<String^>^, IEnumerable<String^>^>
		(	// convert List of String^ to IEnumerable of String^
			query3, PetOwner::getListAsArray
		);
 
	Console::WriteLine("Using SelectMany():");
	IEnumerable<String^>^ query1 =
		Enumerable::SelectMany<IEnumerable<String^>^, String^>
		(	// extract IENumerable of String^ from embedded IEnumerable
			query2, PetOwner::getArrayAsArray
		);
 
	// Only one foreach loop is required to iterate 
	// through the results since it is a
	// one-dimensional collection.
	for each(String^ pet in query1)
	{
		Console::WriteLine(pet);
	}
 
		/*
		This code produces the following output:
 
			Using Select():
			Scruffy
			Sam
 
			Walker
			Sugar
 
			Scratches
			Diesel
 
			Using SelectMany():
			Scruffy
			Sam
			Walker
			Sugar
			Scratches
			Diesel
		*/
}

C++/CLI Join Generic Method Syntax for MSDN

Here is a code snippet for MSDN where the example for C++/CLI under “Join Generic Method” is missing.
The code is slightly different to make more sense (to me) and still can be used in the same spirit.
I changed the List objects to array and added a key field to the classes rather than using the data as the key.
 
#include "stdafx.h"
using namespace System;
using namespace System::Collections::Generic;
using namespace System::Linq; // ref: System.Core
 
public ref class Owner
{
public:
    property String^ Name;
    property String^ Id;
    property DateTime^ FirstVisit;
 
    Owner(String^ Name, String^ Id, DateTime^ FirstVisit)
    {
        this->Name = Name;
        this->Id = Id;
        this->FirstVisit = FirstVisit;
    }
};
 
public ref class Pet
{
public:
    property String^ Name;
    property String^ OwnerId;
 
    Pet(String^ Name, String^ OwnerId)
    {
        this->Name = Name;
        this->OwnerId = OwnerId;
    }
};
 
public ref class OwnerToPet
{
private:
    static String^ _getOwnerKey(Owner^ owner) { return owner->Id; }
    static String^ _getPetKey(Pet^ pet) { return pet->OwnerId; }
    static OwnerToPet^ _getOwnerToPet(Owner^ owner, Pet^ pet)
        { return gcnew OwnerToPet(owner->Name, pet->Name); }
 
public:
    property String^ OwnerName;
    property String^ PetName;
 
    OwnerToPet(String^ OwnerName, String^ PetName)
    {
        this->OwnerName = OwnerName;
        this->PetName = PetName;
    }
 
    static Func<Owner^, String^>^ getOwnerKey = gcnew Func<Owner^, String^>(_getOwnerKey);
    static Func<Pet^, String^>^ getPetKey = gcnew Func<Pet^, String^>(_getPetKey);
    static Func<Owner^, Pet^, OwnerToPet^>^ getOwnerToPet = gcnew Func<Owner^, Pet^, OwnerToPet^>(_getOwnerToPet);
};
 
static void JoinEx1()
{
    array<Owner^, 1>^ owners = 
    {
        { gcnew Owner("Hedlund, Magnus", "MH1", Convert::ToDateTime("05/20/1988")) },
        { gcnew Owner("Adams, Terry", "TA1", Convert::ToDateTime("11/23/1997")) },
        { gcnew Owner("Weiss, Charlotte", "CW1", Convert::ToDateTime("02/05/2001")) }
    };
 
    array<Pet^, 1>^ pets =
    {
        { gcnew Pet("Barley", "TA1") },
        { gcnew Pet("Boots", "TA1") },
        { gcnew Pet("Whiskers", "CW1") },
        { gcnew Pet("Daisy", "MH1") }
    };
 
    auto ownersAndPets =    Enumerable::Join <Owner^, Pet^, String^, OwnerToPet^>
    (
        owners,
        pets,
        OwnerToPet::getOwnerKey,
        OwnerToPet::getPetKey,
        OwnerToPet::getOwnerToPet
    );
 
    for each (OwnerToPet^ ownerAndPets in ownersAndPets)
    {
        Console::WriteLine("{0} - {1}", ownerAndPets->OwnerName, ownerAndPets->PetName);
    }
 
    /*
    This code produces the following output:
    Hedlund, Magnus - Daisy
    Adams, Terry - Barley
    Adams, Terry - Boots
    Weiss, Charlotte - Whiskers
    */
}
 
 

Playing with Static Population in C++/CLI

One of the tougher things I’ve tried in C++/CLI (or C++ in general) is to “statically fill” or “populate as close to compile-time as possible” a class or other object.
If the object is a simple array-type, the syntax is fairly straightforward.  If it is a dot-net type (like an ILookup), it is more difficult.

In C#, I frequently convert collections to ILookup and Dictionary without much trouble.  In CLI, the syntax is more daunting.

Now that Enumerable and I are on speaking terms, I find it easier to make the conversions.
As usual, I create a helper-class to gcnew the Func for the keySelector and valSelector.
This allows for re-use and a cleaner-looking codebase.

A tough point is understanding the template argument list, which for these examples represent:
1) What is an “each” of the collection (this is a collection of…?)
2) What is the return type of the Func generating the key (what is the key-type?)
3) What is the return type of the Func generating the value (what is the value-type?)

Of the array<array<String^, 1>^, 1>^, the “each” is the array<String^, 1>^
So when the Enumerable::ToLookup is called, the template argument list signature is:
   Enumerable::ToLookup<array<String^, 1>^, String^, String^>

Of the ILookup<String^, String^>^, the “each” is the IGrouping<String^, String^>^
So when the is Enumerable::ToDictionary called, the template argument list signature is:
   Enumerable::ToDictionary<IGrouping<String^, String^>^, String^, String^>

Here are a couple of examples demonstrating how to immediately fill an ILookup or Dictionary in C++/CLI.
The trick is to start with an array type construct:
// semi-statically build a lookup from an embedded array of strings
ILookup<String^, String^>^ lkup_s2sData =
  
Enumerable::ToLookup<array<String^, 1>^, String^, String^>(
  
gcnew array<array<String^, 1>^, 1> {
   {
"one", "uno" },
   {
"two", "dos" },
   {
"three", "tres" },
   {
"four", "cuatro" },
   {
"one", "ein" },
   {
"five", "cinco" }
   },
   CStaticFill::getKeyFromArrArr, CStaticFill::getValFromArrArr
);

I’ll switch to screenshots here for continuity.
First, the helper class:
StaticFill.h

Now the code that uses it:
PlayWithStaticFill_CPP

Output:
PlayWithStaticFill_Output

Enumerable::SelectMany from Visual C++

I looked long and hard for a suitable sample of the Enumerable::SelectMany static method in C++, but could not find one. Now, I have one.

Playing With Any vs. Count() greater-than 0 in .Net (Enumerable Extensions)

A visual example of how Any() differs from Count() > 0 in .Net

Using a Predicate as a key to a Dictionary

Using a Predicate as the key to a Dictionary. Eventually creating a program that has no if-statements or for-loops.

Linq Challenge in C++

Taking what seems to be a simple LINQ task (in C#) and converting it to C++.

Programming Forums

 

 

Here is a list of programming forums I visit for:

  • Seeing what programmers are currently learning
  • Seeing what makes programmers struggle
  • Answering programming questions
  • Asking programming questions

The sites require (free) registration and, in different ways, keep track of points you earn for participation as well as a reputation score.

Here they are in no specific order:

  1. http://www.daniweb.com
  2. http://social.msdn.microsoft.com/Forums/
  3. http://stackoverflow.com/
  4. http://stackexchange.com/
  5. http://www.experts-exchange.com/

Releasing Email File Attachment Resources (System.Net.Mail)

Lesson learned about releasing attachment resources with System.Net.Mail.

GridView from LINQ to Objects

A technique for displaying results from LINQ to an ASP.NET GridView.

Ambiguous Symbol -- Compiler Error C2872

How I solved the Ambiguous Symbol -- Compiler Error C2872 problem in C++ (dot net).

ResponseStatusLine protocol violation

This is an example of how to get around the ResponseStatusLine protocol violation in multiple .NET languages and in the app.config file.

Playing with Enumerable.Range (System.Linq)

Here's an example of something fun and useful with Enumerable.Range in four different languages.