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 ) 
    ...
28
demandé sur dtb 2011-02-12 00:26:29

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.

28
répondu Hans Passant 2011-02-11 22:00:39

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());
8
répondu Marcel 2014-09-27 09:15:20

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.

5
répondu Ben Voigt 2011-02-12 00:39:02