2

I'm trying to get a sorted list of all environment variables for logging purpose using System.Environment.GetEnvironmentVariables() which returns an IDictionary.

According to the documentation IDictionary does not provide any functionality for sorting: IDictionary Interface

The IDictionary interface allows the contained keys and values to be enumerated, but it does not imply any particular sort order.

As kind of workaround i came up with something like this:

var dictionary = Environment.GetEnvironmentVariables();

var keyList = dictionary.Keys.OfType<string>().ToList();
keyList.Sort();

int maxKeyLen = keyList.Max(key => ((string)key).Length);

string logMessage = "";

foreach (string key in keyList)
{
    logMessage = 
        logMessage + 
        Environment.NewLine + 
        (key + ": ").PadRight(maxKeyLen + 2) + 
        dictionary[key];
}

Console.WriteLine(logMessage);

Update

Due to the solution of @canton7 I changed the upper code to this:

var sortedEntries = Environment.GetEnvironmentVariables().Cast<DictionaryEntry>().OrderBy(entry => entry.Key);

int maxKeyLen = sortedEntries.Max(entry => ((string)entry.Key).Length);

string logMessage = "";

foreach (var entry in sortedEntries)
{
    logMessage =
        logMessage +
        Environment.NewLine +
        (entry.Key + ": ").PadRight(maxKeyLen + 2) +
        entry.Value;
}

Console.WriteLine(logMessage);
flawesome
  • 322
  • 3
  • 9
  • With this i receive error CS1061 'IDictionary' does not contain a definition for 'OrderBy' and no accessible extension method 'OrderBy' accepting a first argument of type 'IDictionary' could be found (are you missing a using directive or an assembly reference?) GetEnvironmentVariables returns an IDictionary, not an IDictionary – flawesome Mar 25 '22 at 11:56
  • `var sortedKeysAndValues = dictionary.Cast().OrderBy(x => (string)x.Key)`? – canton7 Mar 25 '22 at 11:57
  • It's funny that `dictionary.Cast()` and `dictionary.Keys.OfType()` are essentially identical techniques.. – Caius Jard Mar 25 '22 at 12:09
  • 3
    Environment variables often contain secrets so keep that in mind as you log them. – Crowcoder Mar 25 '22 at 12:19
  • @CaiusJard "*It's funny that `dictionary.Cast()` and `dictionary.Keys.OfType()` are essentially identical techniques..*" - well, except that the former avoids needing to do a lookup for every key – canton7 Mar 25 '22 at 12:20
  • @Crowcoder yes sure, it's not for external use. But thank you for the hint – flawesome Mar 25 '22 at 12:28
  • I meant "techniques for resolving the 'ancient collection implements IE but not IE' problem".. – Caius Jard Mar 25 '22 at 13:52

1 Answers1

8

Environment.GetEnvironmentVariables() returns a non-generic IDictionary. IDictionary implements IEnumerable, and even though this isn't clear from the interface without reading the documentation, every member you get when iterating over it is a DictionaryEntry.

A DictionaryEntry is basically just a pre-generics KeyValuePair<object, object>.

Linq provides two methods for moving from a non-generic IEnumerable to a generic IEnumerable<T>: Cast<T>() and OfType<T>(). In this case, since we know that every element is a DictionaryEntry, we can use Cast<DictionaryEntry>().

So:

var entries = Environment.GetEnvironmentalVariables().Cast<DictionaryEntry>();

Now we've got an IEnumerable<DictionaryEntry>. We could just sort this:

var sortedEntries = entries.OrderBy(x => (string)x.Key);

Or we could turn it into a KeyValuePair<string, string> first to make it easier to work with:

var entries = Environment.GetEnvironmentalVariables().Cast<DictionaryEntry>()
    .Select(x => KeyValuePair.Create((string)x.Key, (string)x.Value));
var sortedEntries = entries.OrderBy(x => x.Key);
canton7
  • 37,633
  • 3
  • 64
  • 77
  • 1
    I suppose it wouldn't even need to be a `KVP` - maybe some anonymous type would be fine? – Caius Jard Mar 25 '22 at 12:14
  • Sure, or a tuple. I chose a `KVP` because it might be more familiar to OP if they're used to working with generic dictionaries, but they can do whatever they want – canton7 Mar 25 '22 at 12:19
  • @canton7 this solution works just fine for my purpose. Thank you very much! – flawesome Mar 25 '22 at 12:47