Paramètres optionnels dans les méthodes gérées C++/CLI
Comment puis-je déclarer une méthode gérée en C++/CLI qui a un paramètre optionnel lorsqu'elle est utilisée à partir de C#?
j'ai décoré le paramètre avec un Facultatif et DefaultParameterValue l'attribut (voir: comment les valeurs des paramètres par défaut sont encodées), mais seul l'attribut optionnel semble être honorer.
C++ / CLI:
public ref class MyClass1
{
public:
MyClass1([System::Runtime::InteropServices::Optional]
[System::Runtime::InteropServices::DefaultParameterValue(2)]
int myParam1) ↑
{
System::Console::WriteLine(myParam1);
}
};
C#:
var myInstance1 = new MyClass1(); // compiles and runs
Sortie:
0
Résultats Escomptés:
2
Visual C# IntelliSense:
MyClass1.MyClass1([int myParam1 = 0]); // wrong default value
↑
Edit: un examen plus attentif avec un démonteur révèle que le compilateur C++/CLI ne génère pas les.param [1] = int32(2)
la directive. Le code IL indiqué par le réflecteur est erroné.
Réflecteur:
.method public hidebysig specialname rtspecialname instance void .ctor([opt] int32 myParam1) cil managed
{
.param [1] = int32(2) // bug
...
ILDASM:
.method public hidebysig specialname rtspecialname instance void .ctor([opt] int32 myParam1) cil managed
{
.param [1]
.custom instance void [System]System.Runtime.InteropServices.DefaultParameterValueAttribute::.ctor(object) = ( 01 00 08 02 00 00 00 00 00 )
...
3 réponses
le compilateur C# n'utilise pas l'attribut [DefaultParameterValue] pour définir la valeur par défaut, il utilise la .directive param pour intégrer la valeur dans les métadonnées. À peine documenté dans la spécification CLI btw, seule la Partition II, chapitre 15.4.1 mentionne qu'il peut avoir une valeur FieldInit, 15.4.1.4 est muet à ce sujet.
C'est là que le buck s'arrête, le compilateur C++/CLI ne sait pas comment générer la directive. Vous ne pouvez pas faire ce travail.
il y a une astuce pour que cela fonctionne (solution de contournement). le mot magique est NULL, car pour les types NULL, la valeur par défaut est toujours" null" (.HasValue = = false)
Exemple:
C++ CLI dans header:
String^ test([Optional] Nullable<bool> boolTest);
C++ cliin .fichier cpp:
String^ YourClass::test(Nullable<bool> boolTest)
{
if (!boolTest.HasValue) { boolTest = true; }
return (boolTest ? gcnew String("True") : gcnew String("False"));
}
à Tester en C#:
MessageBox.Show(YourClass.test());
comme solution de contournement, vous pouvez simplement surcharger le constructeur et utiliser la délégation. Il sera Intim é par le JIT et devrait finir avec le même résultat final qu'un paramètre par défaut.