112 votes

Une propriété ou un indexeur ne peut pas être passé en tant que paramètre out ou ref

Je reçois l'erreur ci-dessus et je n'arrive pas à la résoudre. J'ai fait quelques recherches mais je n'arrive pas à m'en débarrasser.

Scénario :

J'ai de la classe BudgetAllocate dont la propriété est budget qui est de double type.

Dans mon dataAccessLayer ,

C'est ce que j'essaie de faire dans l'une de mes classes :

double.TryParse(objReader[i].ToString(), out bd.Budget);

Ce qui provoque cette erreur :

Une propriété ou un indexeur ne peut pas être passé comme paramètre out ou ref à la commande moment de la compilation.

J'ai même essayé ceci :

double.TryParse(objReader[i].ToString().Equals(DBNull.Value) ? "" : objReader[i].ToString(), out bd.Budget);

Tout le reste fonctionne correctement et les références entre les couches sont présentes.

179voto

Mike Chamberlain Points 5325

D'autres vous ont donné la solution, mais pour ce qui est de la raison pour laquelle cela est nécessaire : une propriété est juste du sucre syntaxique pour un méthode .

Par exemple, lorsque vous déclarez une propriété appelée Name avec un getter et un setter, le compilateur génère en fait des méthodes appelées get_Name() y set_Name(value) . Ensuite, lorsque vous lisez et écrivez dans cette propriété, le compilateur traduit ces opérations en appels aux méthodes générées.

Lorsque vous considérez cela, la raison pour laquelle vous ne pouvez pas passer une propriété en tant que paramètre de sortie devient évidente - vous passeriez en fait une référence à un fichier méthode plutôt qu'une référence à un objet a variable ce qui correspond aux attentes d'un paramètre de sortie.

Il en va de même pour les indexeurs.

74voto

Hans Passant Points 475940

Il s'agit d'un cas d'abstraction non étanche. Une propriété est en fait une méthode, le obtenir y fixer pour un indexeur sont compilés dans les méthodes get_Index() et set_Index. Le compilateur fait un excellent travail pour cacher ce fait, il traduit automatiquement une affectation à une propriété par la méthode set_Xxx() correspondante, par exemple.

Mais cela ne fonctionne plus du tout lorsque vous passez un paramètre de méthode par référence. Le compilateur JIT doit alors passer un pointeur sur l'emplacement mémoire de l'argument passé. Le problème est qu'il n'y en a pas, l'assignation de la valeur d'une propriété nécessite d'appeler la méthode setter. La méthode appelée ne peut pas faire la différence entre une variable passée et une propriété passée et ne peut donc pas savoir si un appel de méthode est nécessaire.

Ce qui est remarquable, c'est que cela fonctionne en fait en VB.NET. Par exemple :

Class Example
    Public Property Prop As Integer

    Public Sub Test(ByRef arg As Integer)
        arg = 42
    End Sub

    Public Sub Run()
        Test(Prop)   '' No problem
    End Sub
End Class

Le compilateur VB.NET résout ce problème en générant automatiquement ce code pour la méthode Run, exprimée en C# :

int temp = Prop;
Test(ref temp);
Prop = temp;

C'est la solution de contournement que vous pouvez également utiliser. Je ne sais pas exactement pourquoi l'équipe C# n'a pas utilisé la même approche. Peut-être parce qu'ils ne voulaient pas cacher les appels potentiellement coûteux des getter et setter. Ou le comportement totalement non diagnostiqué que vous obtiendrez lorsque le setter a des effets secondaires qui modifient la valeur de la propriété, ils disparaîtront après l'assignation. Différence classique entre C# et VB.NET, C# est "sans surprise", VB.NET est "faites en sorte que cela fonctionne si vous le pouvez".

43voto

dhinesh Points 2175

Vous ne pouvez pas utiliser

double.TryParse(objReader[i].ToString(), out bd.Budget); 

remplacer bd.Budget par une variable.

double k;
double.TryParse(objReader[i].ToString(), out k);

13voto

David Hollinshead Points 571

Il pourrait être intéressant de rédiger votre propre texte :

    //double.TryParse(, out bd.Budget);
    bool result = TryParse(s, value => bd.Budget = value);
}

public bool TryParse(string s, Action<double> setValue)
{
    double value;
    var result =  double.TryParse(s, out value);
    if (result) setValue(value);
    return result;
}

10voto

Adam Houldsworth Points 38632

Placez le paramètre out dans une variable locale, puis placez la variable en bd.Budget :

double tempVar = 0.0;

if (double.TryParse(objReader[i].ToString(), out tempVar))
{
    bd.Budget = tempVar;
}

Mise à jour : Directement de MSDN :

P ne peuvent donc pas être transmises en tant que paramètres.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X