Procedura: esporre un contenitore STL/CLR da un assembly
I contenitori STL/CLR come list
e map
vengono implementati come classi di riferimento del modello. Poiché i modelli C++ vengono creati istanze in fase di compilazione, due classi modello che hanno esattamente la stessa firma, ma che si trovano in assembly diversi sono effettivamente tipi diversi. Ciò significa che le classi modello non possono essere usate attraverso i limiti dell'assembly.
Per rendere possibile la condivisione tra assembly, i contenitori STL/CLR implementano l'interfaccia ICollection<T>generica . Usando questa interfaccia generica, tutti i linguaggi che supportano generics, tra cui C++, C# e Visual Basic, possono accedere ai contenitori STL/CLR.
Questo argomento illustra come visualizzare gli elementi di diversi contenitori STL/CLR scritti in un assembly C++ denominato StlClrClassLibrary
. Vengono mostrati due assembly per accedere StlClrClassLibrary
a . Il primo assembly viene scritto in C++e il secondo in C#.
Se entrambi gli assembly sono scritti in C++, è possibile accedere all'interfaccia generica di un contenitore usando il relativo generic_container
typedef. Ad esempio, se si dispone di un contenitore di tipo cliext::vector<int>
, la relativa interfaccia generica è: cliext::vector<int>::generic_container
. Analogamente, è possibile ottenere un iteratore sull'interfaccia generica usando il generic_iterator
typedef, come in: cliext::vector<int>::generic_iterator
.
Poiché questi typedef vengono dichiarati nei file di intestazione C++, gli assembly scritti in altri linguaggi non possono usarli. Pertanto, per accedere all'interfaccia generica per cliext::vector<int>
in C# o in qualsiasi altro linguaggio .NET, usare System.Collections.Generic.ICollection<int>
. Per scorrere questa raccolta, usare un foreach
ciclo.
La tabella seguente elenca l'interfaccia generica implementata da ogni contenitore STL/CLR:
Contenitore STL/CLR | Interfaccia generica |
---|---|
deque<T> |
ICollection<T> |
hash_map<K, V> |
IDictionary<K, V> |
hash_multimap<K, V> |
IDictionary<K, V> |
hash_multiset<T> |
ICollection<T> |
hash_set<T> |
ICollection<T> |
list<T> |
ICollection<T> |
map<K, V> |
IDictionary<K, V> |
multimap<K, V> |
IDictionary<K, V> |
multiset<T> |
ICollection<T> |
set<T> |
ICollection<T> |
vector<T> |
ICollection<T> |
Nota
Poiché i queue
contenitori , priority_queue
e stack
non supportano gli iteratori, non implementano interfacce generiche e non possono essere accessibili tra assembly.
Esempio 1
Descrizione
In questo esempio viene dichiarata una classe C++ che contiene dati membri STL/CLR privati. Dichiariamo quindi metodi pubblici per concedere l'accesso alle raccolte private della classe . Questa operazione viene eseguita in due modi diversi, uno per i client C++ e uno per gli altri client .NET.
Codice
// StlClrClassLibrary.h
#pragma once
#include <cliext/deque>
#include <cliext/list>
#include <cliext/map>
#include <cliext/set>
#include <cliext/stack>
#include <cliext/vector>
using namespace System;
using namespace System::Collections::Generic;
using namespace cliext;
namespace StlClrClassLibrary {
public ref class StlClrClass
{
public:
StlClrClass();
// These methods can be called by a C++ class
// in another assembly to get access to the
// private STL/CLR types defined below.
deque<wchar_t>::generic_container ^GetDequeCpp();
list<float>::generic_container ^GetListCpp();
map<int, String ^>::generic_container ^GetMapCpp();
set<double>::generic_container ^GetSetCpp();
vector<int>::generic_container ^GetVectorCpp();
// These methods can be called by a non-C++ class
// in another assembly to get access to the
// private STL/CLR types defined below.
ICollection<wchar_t> ^GetDequeCs();
ICollection<float> ^GetListCs();
IDictionary<int, String ^> ^GetMapCs();
ICollection<double> ^GetSetCs();
ICollection<int> ^GetVectorCs();
private:
deque<wchar_t> ^aDeque;
list<float> ^aList;
map<int, String ^> ^aMap;
set<double> ^aSet;
vector<int> ^aVector;
};
}
Esempio 2
Descrizione
In questo esempio viene implementata la classe dichiarata nell'esempio 1. Per consentire ai client di usare questa libreria di classi, viene usato lo strumento manifesto mt.exe per incorporare il file manifesto nella DLL. Per informazioni dettagliate, vedere i commenti del codice.
Per altre informazioni sullo strumento manifesto e sugli assembly side-by-side, vedere Compilazione di applicazioni isolate C/C++ e assembly side-by-side.
Codice
// StlClrClassLibrary.cpp
// compile with: /clr /LD /link /manifest
// post-build command: (attrib -r StlClrClassLibrary.dll & mt /manifest StlClrClassLibrary.dll.manifest /outputresource:StlClrClassLibrary.dll;#2 & attrib +r StlClrClassLibrary.dll)
#include "StlClrClassLibrary.h"
namespace StlClrClassLibrary
{
StlClrClass::StlClrClass()
{
aDeque = gcnew deque<wchar_t>();
aDeque->push_back(L'a');
aDeque->push_back(L'b');
aList = gcnew list<float>();
aList->push_back(3.14159f);
aList->push_back(2.71828f);
aMap = gcnew map<int, String ^>();
aMap[0] = "Hello";
aMap[1] = "World";
aSet = gcnew set<double>();
aSet->insert(3.14159);
aSet->insert(2.71828);
aVector = gcnew vector<int>();
aVector->push_back(10);
aVector->push_back(20);
}
deque<wchar_t>::generic_container ^StlClrClass::GetDequeCpp()
{
return aDeque;
}
list<float>::generic_container ^StlClrClass::GetListCpp()
{
return aList;
}
map<int, String ^>::generic_container ^StlClrClass::GetMapCpp()
{
return aMap;
}
set<double>::generic_container ^StlClrClass::GetSetCpp()
{
return aSet;
}
vector<int>::generic_container ^StlClrClass::GetVectorCpp()
{
return aVector;
}
ICollection<wchar_t> ^StlClrClass::GetDequeCs()
{
return aDeque;
}
ICollection<float> ^StlClrClass::GetListCs()
{
return aList;
}
IDictionary<int, String ^> ^StlClrClass::GetMapCs()
{
return aMap;
}
ICollection<double> ^StlClrClass::GetSetCs()
{
return aSet;
}
ICollection<int> ^StlClrClass::GetVectorCs()
{
return aVector;
}
}
Esempio 3
Descrizione
In questo esempio viene creato un client C++ che usa la libreria di classi creata negli esempi 1 e 2. Questo client usa i generic_container
typedef dei contenitori STL/CLR per scorrere i contenitori e visualizzare il relativo contenuto.
Codice
// CppConsoleApp.cpp
// compile with: /clr /FUStlClrClassLibrary.dll
#include <cliext/deque>
#include <cliext/list>
#include <cliext/map>
#include <cliext/set>
#include <cliext/vector>
using namespace System;
using namespace StlClrClassLibrary;
using namespace cliext;
int main(array<System::String ^> ^args)
{
StlClrClass theClass;
Console::WriteLine("cliext::deque contents:");
deque<wchar_t>::generic_container ^aDeque = theClass.GetDequeCpp();
for each (wchar_t wc in aDeque)
{
Console::WriteLine(wc);
}
Console::WriteLine();
Console::WriteLine("cliext::list contents:");
list<float>::generic_container ^aList = theClass.GetListCpp();
for each (float f in aList)
{
Console::WriteLine(f);
}
Console::WriteLine();
Console::WriteLine("cliext::map contents:");
map<int, String ^>::generic_container ^aMap = theClass.GetMapCpp();
for each (map<int, String ^>::value_type rp in aMap)
{
Console::WriteLine("{0} {1}", rp->first, rp->second);
}
Console::WriteLine();
Console::WriteLine("cliext::set contents:");
set<double>::generic_container ^aSet = theClass.GetSetCpp();
for each (double d in aSet)
{
Console::WriteLine(d);
}
Console::WriteLine();
Console::WriteLine("cliext::vector contents:");
vector<int>::generic_container ^aVector = theClass.GetVectorCpp();
for each (int i in aVector)
{
Console::WriteLine(i);
}
Console::WriteLine();
return 0;
}
Output
cliext::deque contents:
a
b
cliext::list contents:
3.14159
2.71828
cliext::map contents:
0 Hello
1 World
cliext::set contents:
2.71828
3.14159
cliext::vector contents:
10
20
Esempio 4
Descrizione
In questo esempio viene creato un client C# che usa la libreria di classi creata negli esempi 1 e 2. Questo client usa i ICollection<T> metodi dei contenitori STL/CLR per scorrere i contenitori e visualizzare il relativo contenuto.
Codice
// CsConsoleApp.cs
// compile with: /r:Microsoft.VisualC.STLCLR.dll /r:StlClrClassLibrary.dll /r:System.dll
using System;
using System.Collections.Generic;
using StlClrClassLibrary;
using cliext;
namespace CsConsoleApp
{
class Program
{
static int Main(string[] args)
{
StlClrClass theClass = new StlClrClass();
Console.WriteLine("cliext::deque contents:");
ICollection<char> iCollChar = theClass.GetDequeCs();
foreach (char c in iCollChar)
{
Console.WriteLine(c);
}
Console.WriteLine();
Console.WriteLine("cliext::list contents:");
ICollection<float> iCollFloat = theClass.GetListCs();
foreach (float f in iCollFloat)
{
Console.WriteLine(f);
}
Console.WriteLine();
Console.WriteLine("cliext::map contents:");
IDictionary<int, string> iDict = theClass.GetMapCs();
foreach (KeyValuePair<int, string> kvp in iDict)
{
Console.WriteLine("{0} {1}", kvp.Key, kvp.Value);
}
Console.WriteLine();
Console.WriteLine("cliext::set contents:");
ICollection<double> iCollDouble = theClass.GetSetCs();
foreach (double d in iCollDouble)
{
Console.WriteLine(d);
}
Console.WriteLine();
Console.WriteLine("cliext::vector contents:");
ICollection<int> iCollInt = theClass.GetVectorCs();
foreach (int i in iCollInt)
{
Console.WriteLine(i);
}
Console.WriteLine();
return 0;
}
}
}
Output
cliext::deque contents:
a
b
cliext::list contents:
3.14159
2.71828
cliext::map contents:
0 Hello
1 World
cliext::set contents:
2.71828
3.14159
cliext::vector contents:
10
20