从方法返回两个值的最佳方法是什么?

时间:2010-05-05 14:21:00

标签: c# methods return-value

当我必须编写返回两个值的方法时,我通常会按照以下代码返回List<string>。或者,如果我必须返回,例如 id和字符串,然后我返回List<object>,然后使用索引编号和重新创建值选择它们。

这种通过索引进行重铸和引用似乎不够优雅,所以我想为返回两个值的方法开发一种新习惯。最好的模式是什么?

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易于阅读,看起来像一个hack让我以一种方式返回第一个变量而另一个变量另一个,这里是我的重构返回一个自定义类

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; }
    }
}

9 个答案:

答案 0 :(得分:12)

我更喜欢创建一个包含两个属性的轻量级类(见下文),或者使用一个元组(现在可以在.NET 4中加入框架但不难编写自己的元组)

class MyReturnValue
{
    public string Id { get; set; }
    public string Name { get; set; }
}

答案 1 :(得分:8)

您可以从4.0开始返回tuple

答案 2 :(得分:2)

使用关键字out

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

方式比投射对象列表的特定元素更好。

答案 3 :(得分:2)

另一种选择是返回KeyValuePair<int, string>

答案 4 :(得分:1)

为什么不public static void GetIdCodeAndFileName(string line, string extension, out string id, out string fileName)

答案 5 :(得分:1)

我要么使用params,要么创建一个带有属性的结构(对于属性初始化器语法)并返回它。创建自定义结构/类具有可变命名的优点,可以匹配传递的数据。这使代码更具可读性。

IdAndString GetIDAndString()
{
    return new IdAndString()
    {
        ID = 1,
        Str = "123"
    };
}

struct IdAndString
{
    public int ID { get; set; }
    public string Str { get; set; } 
}

答案 6 :(得分:1)

我建议使用Mark建议的轻量级物体。但也有其他模式。

另一个简单的方法是,使用reference by reference属性。同样,调用者发送一个空数组作为参数,该数组将由函数填充。

答案 7 :(得分:0)

模板Pair<T,V>怎么样?当然,如果相同的数据类型将被传递,你可以为它构建自定义数据类型,但它不是通用的。

(或者也许C#允许您即时生成类?更新:确定忽略此位

答案 8 :(得分:0)

简单来说,在C#中返回两个值并不是一种优雅的方式。虽然我绝对认为使用out参数比返回List更好,但这不是很易于维护或可读。 C#开发人员期望out,它直接受语言支持,并且很清楚它正在做什么。

从4.0开始,您可以使用Tuple代替。