从方法返回两个值的最佳方式是什么?
当我必须编写返回两个值的方法时,我通常会按照以下返回 List
的代码进行操作。或者,如果我必须返回id和字符串,那么我返回一个List
这种通过索引进行重铸和引用似乎不太优雅,所以我想为返回两个值的方法养成一个新习惯。最好的模式是什么?
using System;
using System.Collections.Generic;
using System.Linq;
namespace MultipleReturns
{
class Program
{
static void Main(string[] args)
{
string extension = "txt";
{
List<string> entries = GetIdCodeAndFileName("first.txt", extension);
Console.WriteLine("{0}, {1}", entries[0], entries[1]);
}
{
List<string> entries = GetIdCodeAndFileName("first", extension);
Console.WriteLine("{0}, {1}", entries[0], entries[1]);
}
Console.ReadLine();
}
/// <summary>
/// gets "first.txt", "txt" and returns "first", "first.txt"
/// gets "first", "txt" and returns "first", "first.txt"
/// it is assumed that extensions will always match
/// </summary>
/// <param name="line"></param>
public static List<string> GetIdCodeAndFileName(string line, string extension)
{
if (line.Contains("."))
{
List<string> parts = line.BreakIntoParts(".");
List<string> returnItems = new List<string>();
returnItems.Add(parts[0]);
returnItems.Add(line);
return returnItems;
}
else
{
List<string> returnItems = new List<string>();
returnItems.Add(line);
returnItems.Add(line + "." + extension);
return returnItems;
}
}
}
public static class StringHelpers
{
public static List<string> BreakIntoParts(this string line, string separator)
{
if (String.IsNullOrEmpty(line))
return null;
else
{
return line.Split(new string[] { separator }, StringSplitOptions.None).Select(p => p.Trim()).ToList();
}
}
}
}
添加:
好的,谢谢大家,我最喜欢“返回自定义类”答案,从来没有真正想过out
很容易阅读,对我来说似乎是一种黑客攻击,以一种方式返回第一个变量,以另一种方式返回第二个变量,这是我返回自定义类的重构:
using System;
using System.Collections.Generic;
using System.Linq;
namespace MultipleReturns
{
class Program
{
static void Main(string[] args)
{
string extension = "txt";
{
IdCodeFileNamePair pair = GetIdCodeAndFileName("first.txt", extension);
Console.WriteLine("{0}, {1}", pair.IdCode, pair.FileName);
}
{
IdCodeFileNamePair pair = GetIdCodeAndFileName("first", extension);
Console.WriteLine("{0}, {1}", pair.IdCode, pair.FileName);
}
Console.ReadLine();
}
/// <summary>
/// gets "first.txt", "txt" and returns "first", "first.txt"
/// gets "first", "txt" and returns "first", "first.txt"
/// it is assumed that extensions will always match
/// </summary>
/// <param name="line"></param>
public static IdCodeFileNamePair GetIdCodeAndFileName(string line, string extension)
{
if (line.Contains("."))
{
List<string> parts = line.BreakIntoParts(".");
List<string> returnItems = new List<string>();
return new IdCodeFileNamePair { IdCode = parts[0], FileName = line };
}
else
{
List<string> returnItems = new List<string>();
return new IdCodeFileNamePair { IdCode = line, FileName = line + "." + extension };
}
}
}
public static class StringHelpers
{
public static List<string> BreakIntoParts(this string line, string separator)
{
if (String.IsNullOrEmpty(line))
return null;
else
{
return line.Split(new string[] { separator }, StringSplitOptions.None).Select(p => p.Trim()).ToList();
}
}
}
public class IdCodeFileNamePair
{
public string IdCode { get; set; }
public string FileName { get; set; }
}
}
When I have to write methods which return two values, I usually go about it as in the following code which returns a List<string>
. Or if I have to return e.g. a id and string, then I return a List<object>
and then pick them out with index number and recast the values.
This recasting and referencing by index seems inelegant so I want to develop a new habit for methods that return two values. What is the best pattern for this?
using System;
using System.Collections.Generic;
using System.Linq;
namespace MultipleReturns
{
class Program
{
static void Main(string[] args)
{
string extension = "txt";
{
List<string> entries = GetIdCodeAndFileName("first.txt", extension);
Console.WriteLine("{0}, {1}", entries[0], entries[1]);
}
{
List<string> entries = GetIdCodeAndFileName("first", extension);
Console.WriteLine("{0}, {1}", entries[0], entries[1]);
}
Console.ReadLine();
}
/// <summary>
/// gets "first.txt", "txt" and returns "first", "first.txt"
/// gets "first", "txt" and returns "first", "first.txt"
/// it is assumed that extensions will always match
/// </summary>
/// <param name="line"></param>
public static List<string> GetIdCodeAndFileName(string line, string extension)
{
if (line.Contains("."))
{
List<string> parts = line.BreakIntoParts(".");
List<string> returnItems = new List<string>();
returnItems.Add(parts[0]);
returnItems.Add(line);
return returnItems;
}
else
{
List<string> returnItems = new List<string>();
returnItems.Add(line);
returnItems.Add(line + "." + extension);
return returnItems;
}
}
}
public static class StringHelpers
{
public static List<string> BreakIntoParts(this string line, string separator)
{
if (String.IsNullOrEmpty(line))
return null;
else
{
return line.Split(new string[] { separator }, StringSplitOptions.None).Select(p => p.Trim()).ToList();
}
}
}
}
Added:
Ok, thanks everyone, I like the "return a custom class" answers best, never really thought out
was that easy to read, seems like a hack to me returning the first variable one way and the second another, here is my refactoring returning a custom class:
using System;
using System.Collections.Generic;
using System.Linq;
namespace MultipleReturns
{
class Program
{
static void Main(string[] args)
{
string extension = "txt";
{
IdCodeFileNamePair pair = GetIdCodeAndFileName("first.txt", extension);
Console.WriteLine("{0}, {1}", pair.IdCode, pair.FileName);
}
{
IdCodeFileNamePair pair = GetIdCodeAndFileName("first", extension);
Console.WriteLine("{0}, {1}", pair.IdCode, pair.FileName);
}
Console.ReadLine();
}
/// <summary>
/// gets "first.txt", "txt" and returns "first", "first.txt"
/// gets "first", "txt" and returns "first", "first.txt"
/// it is assumed that extensions will always match
/// </summary>
/// <param name="line"></param>
public static IdCodeFileNamePair GetIdCodeAndFileName(string line, string extension)
{
if (line.Contains("."))
{
List<string> parts = line.BreakIntoParts(".");
List<string> returnItems = new List<string>();
return new IdCodeFileNamePair { IdCode = parts[0], FileName = line };
}
else
{
List<string> returnItems = new List<string>();
return new IdCodeFileNamePair { IdCode = line, FileName = line + "." + extension };
}
}
}
public static class StringHelpers
{
public static List<string> BreakIntoParts(this string line, string separator)
{
if (String.IsNullOrEmpty(line))
return null;
else
{
return line.Split(new string[] { separator }, StringSplitOptions.None).Select(p => p.Trim()).ToList();
}
}
}
public class IdCodeFileNamePair
{
public string IdCode { get; set; }
public string FileName { get; set; }
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
我更喜欢创建一个具有两个属性的轻量级类(见下文),或者使用元组(现在可以嵌入到 .NET 4 的框架中,但编写自己的属性并不难)
I prefer either to create a lightweight class with two properties (see below), or to use a tuple (now available baked into the framework in .NET 4 but not hard to write your own)
从 4.0 开始,您可以返回 元组。
You could return a tuple, starting with 4.0.
使用关键字
out
http://msdn.microsoft。 com/en-us/library/ee332485.aspx
这比转换对象列表的特定元素方式要好。
Use keyword
out
http://msdn.microsoft.com/en-us/library/ee332485.aspx
This is way better than casting specific elements of a list of objects.
另一种选择是返回
KeyValuePair
。Another option is to return a
KeyValuePair<int, string>
.为什么不使用
public static void GetIdCodeAndFileName(string line, string extension, out string id, out string fileName)
?Why not
public static void GetIdCodeAndFileName(string line, string extension, out string id, out string fileName)
?我要么使用参数,要么创建一个带有属性的结构(对于属性初始值设定项语法)并返回它。创建自定义结构/类的优点是变量命名可以与传递的数据相匹配。这使得代码更具可读性。
I either use out params, or create a struct with properties (for the property initializer syntax) and return that. Creating a custom struct/class has the advantage of variable naming that can match the data being passed. This makes the code more readable.
我建议使用像马克建议的轻量级物体。但也有其他模式。
另一种简单的方法是使用按引用调用属性。就像,调用者发送一个空数组作为参数,该参数将由函数填充。
I would recommend using of a Light weight object like Mark suggested. But there are other patterns as well.
Another simple approach is, use the call by reference property. Like, the caller sends an empty array as a parameter, which will be populated by the function.
模板
Pair
怎么样?当然,如果要传递相同的数据类型,您可以为此构造自定义数据类型,但它不是通用的。(或者 C# 是否允许您即时生成类?更新:可以忽略这一点)
How about a template
Pair<T,V>
? Of course you can construct custom data-types for this if the same ones will be passed around, but it's not as generic.(Or perhaps does C# let you generate classes on-the-fly? update: ok ignore this bit)
在 C# 中,没有一种返回两个值的优雅方法。虽然我绝对认为使用
out
参数比返回List
更好,但这不太可维护或可读。 C# 开发人员期望out
,它由语言直接支持,并且很好地理解它在做什么。从 4.0 开始,您可以使用
Tuple
代替。There just plain isn't an elegant way to return two values in C#. Although I definitely think using
out
parameters is better than returning aList
, that's not very maintainable or readable. C# developers expectout
, it's supported directly by the language, and it's well understood what it's doing.Starting in 4.0, you can use a
Tuple
instead.