函数是否可以返回两个值?

时间:2010-03-12 16:41:38

标签: c#

函数是否可以返回两个值? 如果两个值都是相同的类型,则可以使用数组,但是如何返回两个不同的类型值?

13 个答案:

答案 0 :(得分:39)

函数可以返回2个单独的值吗?不,C#中的函数只能返回单个值。

虽然可以使用其他概念来返回2个值。首先想到的是使用包裹类型,例如Tuple<T1,T2>

Tuple<int,string> GetValues() {
  return Tuple.Create(42,"foo");
}

Tuple<T1,T2>类型仅适用于4.0及更高版本。如果您使用的是早期版本的框架,则可以创建自己的类型或使用KeyValuePair<TKey,TValue>

KeyValuePair<int,string> GetValues() {
  return new KeyValuePair<int,sting>(42,"foo");
}

另一种方法是使用out参数(我会高度推荐元组方法)。

int GetValues(out string param1) {
  param1 = "foo";
  return 42;
}

答案 1 :(得分:13)

总之,没有。

但是你可以为此定义一个struct(或class):

struct TwoParameters {
    public double Parameter1 { get; private set; }
    public double Parameter2 { get; private set; }

    public TwoParameters(double param1, double param2) {
        Parameter1 = param1;
        Parameter2 = param2;
    }
}

这当然对于单个问题来说太具体了。更灵活的方法是定义类似struct的通用Tuple<T1, T2>(如JaredPar建议的那样):

struct Tuple<T1, T2> {
    public T1 Property1 { get; private set; }
    public T2 Property2 { get; private set; }

    public Tuple(T1 prop1, T2 prop2) {
        Property1 = prop1;
        Property2 = prop2;
    }
}

(注意,与上述非常相似的东西实际上是4.0及更高版本中.NET的一部分,显然。)

然后你可能有一些看起来像这样的方法:

public Tuple<double, int> GetPriceAndVolume() {
    double price;
    int volume;

    // calculate price and volume

    return new Tuple<double, int>(price, volume);
}

这样的代码:

var priceAndVolume = GetPriceAndVolume();
double price = priceAndVolume.Property1;
int volume = priceAndVolume.Property2;

答案 2 :(得分:7)

这不是直接可能的。您需要返回一个包装这两个参数的参数,或者使用out参数:

object Method(out object secondResult)
{
    //...

或者:

KeyValuePair<object,object> Method()
{
   // ..

答案 3 :(得分:5)

所有可能的解决方案都错过了一个重点;为什么要从方法返回两个值?我看来,有两种可能的情况; a)你正在返回两个真正应该封装在一个对象中的值(例如,某些东西的高度和宽度,所以你应该返回一个表示某个东西的对象)或者b)这是一个代码气味,你真的需要考虑为什么该方法返回两个值(例如,该方法实际上做了两件事)。

答案 4 :(得分:3)

不直接。您可以选择返回某种自定义结构或具有多个属性的类,如果您只想返回两个值,请使用KeyValuePair,或使用out parameters

答案 5 :(得分:3)

C#7 ,您现在可以返回 ValueTuple

static (bool success, string value) GetValue(string key)
{
    if (!_dic.TryGetValue(key, out string v)) return (false, null);
    return (true, v); // this is a ValueType literal
}

static void Main(string[] args)
{
    var (s, v) = GetValue("foo"); // (s, v) desconstructs the returned tuple
    if (s) Console.WriteLine($"foo: {v}");
}

ValueTuple是一个值类型,与参考类型Tuple相比,它使返回值成为一个很好的选择 - 不需要对象进行垃圾回收。

另请注意,您可以为返回的值指定名称。真的很棒。

仅凭这个原因,我希望可以仅使用一个元素声明ValueTuple。唉,这是不允许的:

static (string error) Foo()
{
    // ... does not work: ValueTuple must contain at least two elements
}

答案 6 :(得分:1)

你基本上(至少)有两个选项,要么除了函数的返回值之外还要创建一个out参数,比如T1 Function(out T2 second),或者你自己的类将这两种类型放在一起,就像这样一个Pair<T1,T2>。我个人更喜欢第二种方式,但这是你的选择。

答案 7 :(得分:1)

在C#中,您可以使用out参数返回多个值。请参阅Int32 struct的TryParse方法中的示例。它在out参数中返回bool和一个整数。

答案 8 :(得分:1)

不,但您可以使用输出参数

 int whatitis;

string stuff = DoStuff(5, out whatitis);

 public string DoStuff(int inParam, out int outParam)
        {
            outParam = inParam + 10;
            return "donestuff";
        }

答案 9 :(得分:0)

除非返回包含多个值的类型(Struct,Dictionary等),否则无法从函数返回多个值。唯一的另一种方法是在传入的参数上使用“out”或“ref”关键字。

答案 10 :(得分:0)

您可以使用out参数。

int maxAge;
int minAge;
public int GetMaxAgeAndMinAge(out int maxAge, out int minAge)
{
    MaxAge = 60;
    MinAge = 0;
    return 1; //irrelevant for this example since we care about the values we pass in
}

我真的倾向于远离这个,我认为这是一种代码味道。它适用于快速和脏。一种更可测试且更好的方法是传递代表您的域的对象(需要看到两个这两个值)。

答案 11 :(得分:0)

你可以试试这个

public IEnumerable<string> Get()
 {
     return new string[] { "value1", "value2" };
 }

答案 12 :(得分:0)

要返回2个值,我通常使用http://blog.o-x-t.com/2007/07/16/generic-pair-net-class/中的Pair类。 如果您需要从描述范围的方法2值返回,例如从/到或最小/最大,您可以use FromToRange class

public class FromToRange<T>
    {
        public T From { get; set; }
        public T To { get; set; }

        public FromToRange()
        {
        }

        public FromToRange(T  from, T  to)
        {
            this.From = from;
            this.To = to;
        }
        public override string ToString()
        {
            string sRet = String.Format("From {0} to {1}", From, To);
            return sRet;
        }
        public override bool Equals(object obj)
        {
            if (this == obj) return true;
            FromToRange<T> pair = obj as FromToRange<T>;
            if (pair == null) return false;
            return Equals(From, pair.From) && Equals(To, pair.To);
        }

        public override int GetHashCode()
        {
            return (From != null ? From.GetHashCode() : 0) + 29 * (To != null ? To.GetHashCode() : 0);
        }

    }