-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathreturn-multiple-values-from-function.html
357 lines (337 loc) · 15.9 KB
/
return-multiple-values-from-function.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
<!DOCTYPE html>
<html lang="en-US" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<title>Return multiple values from a function in C#</title>
<link rel="shortcut icon" href="/wwwroot/favicon.ico" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="language" content="en" />
<meta name="keywords" content="" />
<meta name="description" content="Return multiple values from a function in C#" />
<meta name="author" content="Adrien Torris" />
<meta name="robots" content="index,follow" />
<meta name="generator" content="No404! 0.1" />
<link rel="alternate" href="https://adrientorris.github.io/fr/csharp/retourner-plusieurs-valeurs-de-sortie-methode-csharp.html" hreflang="fr-fr" />
<link rel="alternate" href="https://adrientorris.github.io/csharp/return-multiple-values-from-function.html" hreflang="en-en" />
<link href="/wwwroot/css/style.css" rel="stylesheet" />
<script defer src="https://use.fontawesome.com/releases/v5.0.7/js/all.js"></script>
</head>
<body>
<div id="main_ctn" class="post_ctn">
<header>
<div id="header-content">
<h2>Blog</h2><ul id="social_links">
<li id="twitter_link">
<a href="https://twitter.com/AdrienTorris" target="_Blank" rel="nofollow" title="Adrien Torris sur Twitter">
<i class="fab fa-twitter fa-2x"></i>
</a>
</li>
<li id="github_link" title="Adrien Torris sur GitHub">
<a href="https://github.com/AdrienTorris" target="_Blank" rel="nofollow">
<i class="fab fa-github fa-2x"></i>
</a>
</li>
<li id="so_link">
<a href="https://stackoverflow.com/users/story/4428633" target="_Blank" rel="nofollow" title="Adrien Torris sur StackOverflow">
<i class="fab fa-stack-overflow fa-2x"></i>
</a>
</li>
<li id="linkedin_link">
<a href="https://www.linkedin.com/in/adrientorris/" target="_Blank" rel="nofollow" title="Adrien Torris sur LinkedIn">
<i class="fab fa-linkedin fa-2x"></i>
</a>
</li>
<li id="gplus_link">
<a href="https://plus.google.com/u/0/+AdrienTorris" target="_Blank" rel="nofollow" title="Adrien Torris sur Google Plus">
<i class="fab fa-google-plus-g fa-2x"></i>
</a>
</li>
</ul>
<ul id="flags_wrapper">
<li><a href="https://adrientorris.github.io/fr/csharp/retourner-plusieurs-valeurs-de-sortie-methode-csharp.html" title=""><img src="/wwwroot/images/french.png" alt="" title="" /></a></li>
<li class="cur"><img src="/wwwroot/images/english.jpg" alt="" title="" /></li>
</ul>
</div>
</header>
<div id="arianne_wrapper">
<ul>
<li><a href="https://adrientorris.github.io/index.html" title="">Home</a></li>
<li>C#</li>
<li class="active"><a href="https://adrientorris.github.io/csharp/return-multiple-values-from-function.html" title="Return multiple values from a function in C#">Return multiple values from a function in C#</a></li>
</ul>
</div>
<div id="post_ctn">
</div>
<div id="post_ctn">
<h1>Return multiple values from a function in C#</h1>
<p>Il y a plusieurs manières en C# d'implémenter une méthode renvoyant plusieurs valeurs. En voici quelque-unes, avec autant d'information que possible sur chacunes d'entre-elles.</p>
<ul>
<li>
<span class="step_number">1</span>
<h2>Using class</h2>
Ce procédé, probablement le plus courant, est d'utiliser une classe comme valeur de retour. Vous êtes ainsi totalement libre de retourner ce que bon vous semble, puisque c'est vous qui définissez entièrement l'objet qui sera retourné.</p>
<pre><code class="csharp">
public sealed class MyReturnContainer
{
public Guid GuidValue { get; }
public string StringValue { get; }
public int IntValue { get; }
public MyReturnContainer(Guid g, string s, int i){
GuidValue = g;
StringValue = s;
IntValue = i;
}
}
</code></pre>
<pre><code class="csharp">
public class AnotherClassSomewhereInYourCode
{
public AnotherClassSomewhereInYourCode()
{ }
public MyReturnContainer GetMultipleValues(){
return new MyReturnContainer(Guid.NewGuid(), "string value", 1);
}
}
</code></pre>
<p>
<h3>Benefits :</h3>
<ul>
<li>Flexibilité totale</li>
<li>Supporte l'asynchronisme</li>
</ul>
<h3>Cons of returning a class :</h3>
<ul>
<li>Les classes sont de type référence (moins performant que le type valeur)</li>
<li>Si la classe n'a pas de vrai sens métier ou n'est utilisée qu'une seule fois, cela peut alourdir votre modèle inutilement</li>
</ul>
</p>
</li>
<li>
<span class="step_number">2</span>
<h2>Utiliser les paramètres de sortie (<span class="thnclwrd">out</span>)</h2>
<p>Les paramètres de sortie permettent de déclarer qu'une méthode a une, ou plusieurs valeurs de sortie en plus de sa valeur de retour.</p>
<p>Un paramètre <span class="thnclwrd">out</span> indique au compilateur que l'objet ne sera initialisé qu'à l'intérieur de la fonction, un paramètre out ne peut donc être qu'une valeur de sortie car sa valeur ne peut pas être initialisée en amont. D'autre part, une méthode ayant des paramètres <span class="thnclwrd">out</span> devra obligatoirement leur attribuer une valeur à tous. Une méthode ayant des paramètres out non-assignés engendrera une erreur de compilation.</p>
<pre><code class="csharp">
Guid myGuid = Guid.Empty;
string myString = string.Empty;
int myInt = 0;
public bool GetMultipleValues(out Guid g, out string s, out int i){
g = Guid.NewGuid();
s = "string value";
i = 1;
return true;
}
bool ret = GetMultipleValues(out myGuid, out myString, out myInt);
Console.WriteLine(myString); // "string value"
</code></pre>
<p>A noter qu'un paramètre <span class="thnclwrd">out</span> peut être nullable.</p>
<pre><code class="csharp">
public bool TryCreateSomething(string param1, string param2, bool param3, out Guid? id){
id = null;
// do something
return true;
}
</code></pre>
<p>Enfin, avec C# 7.0, les paramètres se sortie n'ont plus à être déclarées avant leur passage en paramètres mais peuvent l'être à la volée, comme ceci :</p>
<pre><code class="csharp">
public void PrintCoordinates(Point p)
{
p.GetCoordinates(out int x, out int y);
Console.WriteLine($"({x}, {y})");
}
</code></pre>
<p>
<h3>Benefits :</h3>
<ul>
<li>Flexibilité</li>
</ul>
<h3>Inconvénients :</h3>
<ul>
<li>Ne supporte pas l'asynchronisme</li>
<li>Obligation d'assigner une valeur, même nulle</li>
</ul>
</p>
</li>
<li>
<span class="step_number">3</span>
<h2>Utiliser les paramètres de sortie par référence (<span class="thnclwrd">ref</span>)</h2>
<p>Passer un ou plusieurs paramètres par référence a pour effet que toute modification de valeur qui sera effectuée au sein d'une méthode sera répercutée sur la variable d'origine, en dehors de la méthode.</p>
<p>Contrairement aux paramètres de sortie (<span class="thnclwrd">out</span>), tout paramètre passé en référence à une méthode doit être préalablement initialisé mais ne doit pas forcemment voir une valeur lui être assignée par cette même méthode.</p>
<p>Un paramètre <span class="thnclwrd">ref</span> ayant une valeur avant-même l'exécution d'une méthode, on dit que c'est un paramètre double-sens (two-ways), car sa valeur peut être utilisée au sein d'une méthode, même si cette dernière ne lui a encore rien assigné.</p>
<pre><code class="csharp">
string message = "Hello";
public void AlterMyMessage(ref string message){
message = "Hi there !";
}
Console.WriteLine(message); // "Hello"
AlterMyMessage(ref message);
Console.WriteLine(message); // "Hi there !"
</code></pre>
<p>
<h3>Benefits :</h3>
<ul>
<li>Flexibilité</li>
<li>Double-sens</li>
</ul>
<h3>Inconvénients :</h3>
<ul>
<li>Ne supporte pas l'asynchronisme</li>
</ul>
</p>
</li>
<li>
<span class="step_number">4</span>
<h2>Les Tuple</h2>
<p>Apparus avec le Framework .NET 4.0, les <span class="thnclwrd">Tuple</span> permettent de créer des objets sur-mesures et complexes sans pour autant avoir à déclarer une classe. Ils peuvent contenir autant de paramètres que vous le souhaitez (le framework .NET pends en charge jusqu'à 7 éléments, mais vous pouvez outrepasser cette limitation en imbriquant des <span class="thnclwrd">Tuple</span> dans la propriété <span class="thnclwrd">Rest</span> d'un <span class="thnclwrd">Tuple</span>), de tout type. A leur utilisation, ces paramètres seront nommés Item<i>X</i>, <i>X</i> étant leur position (Item1 pour le premier paramètre, Item2 pour le deuxième, etc).</p>
<pre><code class="csharp">
class TupleExample
{
static void Main()
{
// Instanciation d'un Tuple à 3 paramètres
Tuple<int, string, bool> tuple = new Tuple<int, string, bool>(10, "string value", true);
// Accès aux propriétés du Tuple créé
if (tuple.Item1 == 10)
{
Console.WriteLine(tuple.Item1);
}
if (tuple.Item2 == "string")
{
Console.WriteLine(tuple.Item2);
}
if (tuple.Item3)
{
Console.WriteLine(tuple.Item3);
}
}
}
</code></pre>
<p>Techniquement, un <span class="thnclwrd">Tuple</span> est une classe qui fournit des méthodes statiques pour créer des instances.</p>
<p>Si cet objet s'avère extrêmement pratique et utile dans bon nombre de cas, il est à noter qu'il est tout de même à utiliser avec parcimonie, n'étant pas toujours facile à maintenir dans le temps. En effet, il est parfois difficile lorsqu'on repasse sur une méthode 2 ans après l'avoir écrite, de se souvenir à quoi correspondent les propriétés Item4, Item5 et Item6 ... Cela dit, il semble que ce ne sera pas une limitation encore longtemps, comme l'atteste cette <a href="https://github.com/dotnet/roslyn/issues/347" title="" target="_Blank">issue GitHub</a>. Qui plus est, si vous décidez d'ajouter un paramètre en deuxième position, alors les noms de tous les paramètres suivants seront impactés.</p>
<p>
<h3>Benefits :</h3>
<ul>
<li>Evite d'alourdir le modèle inutilement</li>
<li>Flexibilité totale</li>
<li>Supporte l'asynchronisme</li>
</ul>
<h3>Inconvénients :</h3>
<ul>
<li>Dénomination abstraite des propriétés</li>
<li>Maintenabilité</li>
<li>Performance (type référence)</li>
</ul>
</p>
</li>
<li>
<span class="step_number">5</span>
<h2>Utiliser une entrée de dictionnaire (KeyValuePair)</h2>
<pre><code class="csharp">
class KeyValuePairExample
{
static void Main()
{
KeyValuePair<int, string> kvp = GetKeyValuePair();
}
KeyValuePair<int, string> GetKeyValuePair(){
return new KeyValuePair<int, string>(1, "string value");
}
}
</code></pre>
<p>
<h3>Benefits :</h3>
<ul>
<li>Facilité d'utilisation (classe implémentant déjà certaines méthodes de requêtage, et autres)</li>
<li>Supporte l'asynchronisme</li>
<li>Unicicité des coupes clé/valeur (en cas de dictionnaire)</li>
</ul>
<h3>Cons of returning a KeyValuePair :</h3>
<ul>
<li>Performance (moins performant qu'un Tuple de 2 paramètres, ou qu'une structure)</li>
</ul>
</p>
</li>
<li>
<span class="step_number">6</span>
<h2>Utiliser une structure (<span class="thnclwrd">struct</span>)</h2>
<p>Les structures sont des alternatives aux classes, et sont de type valeur, contrairement aux classes qui sont de type référence. Si les structures ont bien plus de limitations que les classes, elles sont bien plus performantes, raison pour laquelle il est préférable d'utiliser des structures quand vous le pouvez, surtout si la structure de données en question aura un volume d'instanciations important.</p>
<p>Principales limitations des structures par rapport aux classes :
<ul>
<li>Héritage impossible</li>
<li>Toutes les propriétés doivent avoir une valeur</li>
<li>Les constructeurs sans paramètres sont impossibles (il avaient été ajouté dans C# 6 mais retirés depuis, et ne sont à priori pas à l'étude pour C# 7)</li>
<li>Tout constructeur doit assigner une valeur à chaque propriété de la structure (sinon la valeur par défaut du type sera assignée)</li>
</ul>
</p>
<pre><code class="csharp">
public struct Point
{
public int x, y;
// Constructor:
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
// Override the ToString method:
public override string ToString()
{
return(String.Format("({0},{1})", x, y));
}
}
</code></pre>
<p>
<h3>Benefits :</h3>
<ul>
<li>Type valeur (performance++)</li>
<li>Simplicité</li>
<li>Supporte l'asynchronisme</li>
</ul>
<h3>Cons of returning a structure :</h3>
<ul>
<li>Rigidité de l'objet</li>
</ul>
</p>
</li>
</ul>
<div id="crdny">
22/10/2016
</div>
<div id="tags_wrapper">
<ul>
<li>C#</li>
<li>Csharp</li>
</ul>
</div>
<div id="refs_wrapper">
<ul>
<li><a href="https://msdn.microsoft.com/fr-fr/library/s1ax56ch(v=vs.90).aspx" title="Types valeur (Référence C#)" target="_Blank">Types valeur (Référence C#)</a></li>
<li><a href="https://msdn.microsoft.com/fr-fr/library/490f96s2(v=vs.90).aspx" title="Types référence (Référence C#)" target="_Blank">Types référence (Référence C#)</a></li>
</ul>
</div>
</div>
<footer>
</footer>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js" type="text/javascript"></script>
<script src="/wwwroot/js/Infra.js" type="text/javascript"></script>
<link type="text/css" rel="stylesheet" href="/wwwroot/lib/highlight/styles/vs.css" />
<script type="text/javascript" src="/wwwroot/lib/highlight/highlight.pack.js"></script>
<script type="text/javascript">hljs.initHighlightingOnLoad();</script>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-85948839-1', 'auto');
ga('send', 'pageview');
</script>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-F924P8Y6HC"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-F924P8Y6HC');
</script>
</body>
</html>