2010-06-27 23 views
18

Pour autant que je sache, la seule utilisation pour les paramètres out est qu'un appelant peut obtenir plusieurs valeurs de retour à partir d'une seule invocation de méthode. Mais nous pouvons également obtenir plusieurs valeurs de résultat en utilisant les paramètres ref à la place!Dans quelles situations les paramètres 'out' sont-ils utiles (où 'ref' ne peut pas être utilisé à la place)?

Y a-t-il d'autres situations où les paramètres out pourraient s'avérer utiles et où nous ne pourrions pas utiliser les paramètres ref à la place?

Merci.

+0

NB: Je viens de poster [cette réponse] (http://stackoverflow.com/questions/4102892/real-world-examples-where-c-out-parameters-are-useful/7220754#7220754) pour une question similaire où je décris un scénario où un paramètre 'out' est utile pour autre chose que de renvoyer plus d'une valeur d'une méthode. – stakx

Répondre

29

Oui - la différence entre ref et out est en termes d'affectation précise:

  • Un paramètre outn'a pas doivent être définitivement attribué par l'appelant avant l'appel de méthode. Il doit être définitivement affecté dans la méthode avant qu'il ne retourne normalement (c'est-à-dire sans exception). La variable est alors définitivement affectée dans l'appelant après l'appel.

  • Un paramètre doit être définitivement affecté par l'appelant avant l'appel de méthode. Il ne doit pas être affecté une valeur différente dans la méthode.

Nous voulions supposer changer int.TryParse(string, out int) utiliser ref à la place. Habituellement, le code d'appel ressemble à ceci:

int value; 
if (int.TryParse(text, out value)) 
{ 
    // Use value 
} 
else 
{ 
    // Do something else 
} 

Maintenant, si nous avons utilisé ref, nous aurions dû donner value une valeur avant l'appel, par exemple:

int value = 0; 
if (int.TryParse(text, ref value)) 
{ 
    // Use value 
} 
else 
{ 
    // Do something else 
} 

Il est évident que ce n'est pas un énorme différence - mais cela donne une mauvaise impression. Nous assignons une valeur que nous n'avons jamais l'intention d'utiliser, et ce n'est pas une bonne chose pour la lisibilité. Un paramètre out indique qu'une valeur sortira de la méthode (en supposant qu'il n'y a pas d'exception) et que vous n'avez pas besoin d'avoir une valeur pour commencer. Une fois des suggestions que j'ai faites pour C# 5 (je ne sais pas si elle sera prise ou non) est qu'une méthode avec un paramètre out devrait être considérée comme une méthode retournant un tuple des valeurs. Combiné avec un meilleur soutien pour tuples, cela signifierait que nous pourrions faire quelque chose comme ceci:

var (ok, value) = int.TryParse(text); 

Dans ce cas ok et value serait tapé implicitement bool et int respectivement. De cette façon, il est clair ce qui se passe dans la méthode (text) et ce qui sort (deux informations: ok et value).

Ce serait tout simplement pas disponible si int.TryParse utilisé un paramètre ref à la place - comme le compilateur ne peut pas savoir s'il va effectivement soin de la valeur initiale du paramètre ref.

+0

+1 - J'aime l'idée d'une valeur de résultat de tuple impliquée par des paramètres out. – Thomas

+1

@Thomas: Ce n'est pas original - je l'ai pincé de F # :) –

+1

_ (Un peu hors-sujet:) _ D'accord avec Jon sur sa demande de tuple "déballage" (whatdoyoucallit). Je ne comprends toujours pas pourquoi on a fait autant de bruit sur le support des tuples dans .NET/C# 4.0 - et qu'ils ont apparemment même dû adapter le CLR pour cela - alors qu'en même temps cette fonctionnalité très pratique était laissée en dehors. Une sorte de type Tuple semble très trivial, voire presque inutile. – stakx

2

Un paramètre out est utile lorsque vous souhaitez plusieurs valeurs de résultat d'une méthode. Techniquement, vous pouvez utiliser un paramètre ref pour atteindre le même objectif, mais un paramètre out fait un travail nettement meilleur à l'intention de transport. Lorsque vous utilisez ref, il n'est pas clair pourquoi vous le faites au lieu d'utiliser out ou au lieu d'utiliser le résultat de la fonction. Vraisemblablement, vous avez l'intention de changer la valeur transmise, mais pourquoi vous la modifiez n'est pas clair simplement à partir de la signature de la fonction.

8

Vous pouvez examiner les paramètres de cette façon:

  • paramètres normaux sont dans paramètres:
    Une valeur peut aller dans la fonction par un tel paramètre; par conséquent, il doit être initialisé.

  • paramètres ref sont en-dehors paramètres:
    Une valeur peut aller dans et hors d'une fonction par un tel paramètre. A cause du premier, il doit aussi être initialisé.

  • paramètres out sont sur paramètres:
    Une valeur est seulement supposé revenir d'une fonction par un tel paramètre; par conséquent, il n'a pas besoin d'être initialisé.

je suis venu avec cette façon de voir les paramètres ref/out en étudiant la technologie COM de Microsoft. IDL (langage de description d'interface) est utilisé pour décrire les interfaces de composants COM, et avec IDL, les paramètres sont augmentés avec in, out et inout. Je soupçonne que .NET et C# ont partiellement hérité de ces déclarants de COM, bien qu'avec des noms légèrement différents (ref au lieu de inout). Avec COM, out les paramètres sont fréquemment utilisés pour récupérer la valeur de retour réelle d'une méthode d'interface, puisque la valeur de retour «réelle» est souvent déjà utilisée pour renvoyer un code de succès/erreur HRESULT.

Avec.NET, je pense que out paramètres ont beaucoup moins d'importance, même dans les cas où vous voulez retourner plusieurs valeurs d'une méthode (vous pouvez retourner des objets complexes ou Tuple s dans ces situations).

2

Je pense qu'un bel exemple est int.TryParse()

http://msdn.microsoft.com/en-us/library/f02979c7.aspx

La principale raison qui sur est mieux que ref est que vous n'avez pas besoin d'attribuer une valeur factice à le retour var avant d'appeler (même implicitement).

Donc out vous dit, et le compilateur: "Cette var sera assignée dans la méthode et la valeur initiale de la var, le cas échéant, ne sera même pas regardée."

0

différence majeure entre les deux est que si nous utilisons ref alors nous devons initialiser ce avant l'appel et il est en option que nous attribuons une valeur à notre ref variable dans notre méthode.

Cependant pour out nous n'avons pas besoin de les initialiser explicitement mais dans notre méthode nous devons lui assigner une certaine valeur, sinon ils vont générer une erreur de compilation.