Initialize static Dictionary while creating in C++

2020-07-06 03:25发布

问题:

Today I saw C# code that creates static dictionary and initializes it:

public static readonly Dictionary<string, string> dict = new Dictionary<string, string>()
        {
            {"br","value1"},
            {"cn","value2"},
            {"de","value3"},
        };

but when I decided to write same code for C++/CLI, an error occurred. Here is my attempt:

static System::Collections::Generic::Dictionary<System::String^, System::String^>^ dict = gcnew System::Collections::Generic::Dictionary<System::String^, System::String^>( )
    {
        {"br","value1"},
        {"cn","value2"},
        {"de","value3"},
    };

Can I do this and if so, how?

回答1:

C# 3.0 and later allows users to define an "initializer"; for collections, that's a series of elements, which for Dictionaries is streamlined to keys and values. C++.NET to my knowledge does not have this language feature. See this question: it's very similar: Array initialization in Managed C++. Array initializers are the ONLY such initializer in C++; other collections do not offer them in C++.

Basically, your main option is to declare a static constructor and initialize your dictionary in there.



回答2:

This type of Dictionary<T> initialization is a feature not of the class itself, but of the C# compiler. It translates it into separate statements for creation of the Dictionary<T> object, and the creation and addition of each key/value pair. I don't believe the C++ compiler offers the same capabilities.



回答3:

My approach is (.NET 4.5):

// file.h
using namespace System;
using namespace System::Collections::Generic;
// SomeClass
public://or private:
    static Dictionary<String^, String^>^ dict = dictInitializer();
private:
    static Dictionary<String^, String^>^ dictInitializer();

// file.cpp
#include "file.h"
Dictionary<String^, String^>^ SomeClass::dictInitializer(){
    Dictionary<String^, String^>^ dict = gcnew Dictionary<String^, String^>;
    dict->Add("br","value1");
    dict->Add("cn","value2");
    dict->Add("de","value3");
    return dict;
}


回答4:

It is possible! :-)
Not straight-forward, but with a tiny helper function you can create and init a dictionary in one line of code:

// helper class
generic <class TKey, class TValue>
ref class CDict
{
public:
  static Dictionary<TKey, TValue>^ CreateDictionary (...array<KeyValuePair<TKey, TValue>>^ i_aValues)
  {
    Dictionary<TKey, TValue>^ dict = gcnew Dictionary<TKey, TValue>;
    for (int ixCnt = 0; ixCnt < (i_aValues ? i_aValues->Length : 0); ixCnt++)
      dict->Add (i_aValues[ixCnt].Key, i_aValues[ixCnt].Value);
    return dict;
  }
};

// Test
ref class CTest
{
public:
  static Dictionary<int, String^>^ ms_dict = CDict<int, String^>::CreateDictionary (gcnew array<KeyValuePair<int, String^>>
  {
    KeyValuePair<int, String^>(1, "A"),
    KeyValuePair<int, String^>(2, "B")
  });
};

int main()
{
  for each (KeyValuePair<int, String^> kvp in CTest::ms_dict)
    Console::WriteLine (kvp.Key.ToString() + " " + kvp.Value);
}

Tested, working.