C#同一函數返回多個值的解決方法總結


一、前言

  最近在做項目的過程中,涉及到一個函數要求返回多個值的問題,經過一番折騰,問題得到了解決。但我覺得這個問題具有代表性,以后還會遇到這樣的問題,本着學習的目的,通過查閱一些資料,來對函數返回多個值得解決方法進行一下總結,以期能有所收獲,並與各位園友探討學習。

二、函數返回多個值方法(一)使用out返回多個值

  在介紹out使函數返回多個值之前,我們首先來對C#中的ref關鍵字和out關鍵字進行一下介紹

  我們在調用函數時,通常都是向函數中傳遞值,函數獲得的時我們傳遞的這些值的拷貝函數執行時,使用的的是這些拷貝,函數執行結束,這些拷貝也就自然消失,而原來的值不會受到影響。當然這是通常情況,另一種情況是我們向函數傳遞參數,也就是使用ref(引用)和out(輸出)。

  有時候,我們需要改變原來變量的值,這時候我們就需要向函數傳遞變量引用,引用是一個變量並可以訪問原變量的值修改引用就修改了原來變量的值。這里需要對這一原理進行一下解釋,這個原理其實很簡單,即為:變量的值存儲在計算機內存中,可以創建一個引用指向計算機中的變量在內存中的位置,所以當引用被修改時,其實修改的是內存中的值,因此變量的值也就被修改了,但我們調用一個含有引用參數的函數時,函數中的參數將指向傳遞給函數的變量,從而導致修改參數變量的值的同時原來變量的值也就被修改。這樣一解釋,是不是現在就更明白了。話不多說,下面,我們將通過實例的方式,來演示ref關鍵字的用法。

  使用ref進行參數引用傳遞的實例代碼如下:

namespace ShareResourceContract
{
    public class MultipleOutPut
    {
        public double MathCalculation(ref double x)
        {
            x = x * x;
            return x;
        }

    }
}
static void Main(string[] args)
{
            MultipleOutPut output = new MultipleOutPut();
            double a = 5;  //使用ref傳遞變量引用必須在函數體外初始化,不然編譯不會通過
            double b = 3;
            Console.WriteLine("Before:a={0},b={1}", a, b);
            output.MathCalculation(ref a);
            Console.WriteLine("After:a={0},b={1}", a, b);
            Console.ReadLine();
}

  輸出結果如下:

  通過以上實例,我們可以看到,原來變量a的值已經被修改了。

  通過以上的介紹,相信大家對變量引用傳遞參數已經有了一個更深層次的理解。接下來我們繼續介紹,有時候,我們希望一個函數返回多個值,雖然使用ref也可以實現,但C#專門提供了一個專門out關鍵字來處理函數返回多值得問題,以下我們同樣用實例的方式來對其展開介紹。

  使用out關鍵字返回多個值得實例代碼如下:

namespace ShareResourceContract
{
    public class MultipleOutPut
    {
        public double MathCalculation(ref double x)
        {
            x = x * x;
            return x;
        }

        public void MulOutPut(double x,out double add,out double subtract,out double squar)
        {
            add = x + x;
            subtract = x - 5;
            squar = x * x;

        }
    }
}
 static void Main(string[] args)
{

            MultipleOutPut output = new MultipleOutPut();
            double x = 8;
            double add = 0;
            double subtract = 0;
            double squar = 0;
            Console.WriteLine("Before:x={0}", x);
            Console.WriteLine("Before:add={0}", add);
            Console.WriteLine("Before:subtract={0}", subtract);
            Console.WriteLine("Before:squar={0}", squar);

            output.MulOutPut(x, out add, out subtract, out squar);
           
            Console.WriteLine("After:x={0}", x);
            Console.WriteLine("After:add={0}", add);
            Console.WriteLine("After:subtract={0}", subtract);
            Console.WriteLine("After:squar={0}", squar);
            Console.ReadLine();
}

  輸出結構如下:

  通過以上實例可以看出,使用out關鍵字,使函數返回了多個返回值,

  下面我們來對ref和out的區別進行以下說明:

  1、用ref引用的變量在調用函數之前必須初始化,相當於在函數外部實例化,函數里面只是對這個對象進行修改的過程;

  2、而out指定的參數可以不必在函數調用之前初始化,不管有沒有在函數外部被初始化,out指定的參數將在函數內部被清空,並在函數內部進行初始化。

  3、二者的區別可以簡單理解為:“ref有進有出,而out只出不進”。

三、函數返回多個值方法(二)使用Tuple返回多個值

  通過以上介紹,相信大家已經對C#使用關鍵字ref和out使函數返回多個值有了一個深層次的理解,其實C#中除了使用ref和out關鍵字使函數返回多個值之外,還有一種方法也能實現同樣的目的,那就是使用Tuple(元組)返回多個值。話不多說,接下來,我們將就使用Tuple使函數返回多個值展開詳細介紹。

  首先,我們先來回顧一下Tuple,Tuple是C# 4.0時出的新特性,.Net Framework 4.0以上版本可用。元組(Tuple)是一種數據結構,具有特定數量和元素序列。創建對應的元組可以表示一組數據,例如創建具有StudentCode、Name、Age、Sex四元組數據來存儲學生基本信息。

1、創建元組的方法

(1)利用構造函數創建元組(注意:默認情況.Net Framework元組僅支持1到7個元組元素,如果有8個元素或者更多,需要使用Tuple的嵌套和Rest屬性去實現)

var tupleTest1 = new Tuple<int, int, int, int, int, int,int>(1, 2, 3, 4, 5, 6,7);
Console.WriteLine($"Item 1: {tupleTest1.Item1}, Item 7: {tupleTest1.Item7}");

var tupleTest2= new Tuple<int, int, int, int, int, int, int, Tuple<int, int, int>>(1, 2, 3, 4, 5, 6, 7, new Tuple<int, int, int>(8, 9, 10));
Console.WriteLine($"Item 1: {tupleTest2.Item1}, Item 10: {tupleTest2.Rest.Item3}");

(2)利用Tuple靜態方法構建元組(最多支持八個元素

var tupleTest13=Tuple.Create<int, int, int, int, int, int,int>(1, 2, 3, 4, 5, 6,7);
Console.WriteLine($"Item 1: {tupleTest1.Item1}, Item 7: {tupleTest1.Item7}");

var tupleTest4=Tuple.Create<int, int, int, int, int, int, int, int>(1, 2, 3, 4, 5, 6, 7, 8);
Console.WriteLine($"Item 1: {tupleTest2.Item1}, Item 8: {tupleTest2.Rest.Item1}");

2、代替out從函數中返回多個值

  通常,我們需要從函數中返回多個值時,使用out關鍵字輸出參數。學習了Tuple之后,就可以使用Tuple代替out實現從函數中返回多個值了。例如:

using System;

namespace ShareResourceContract
{
    public class MultipleOutPut
    {
     
       public Tuple<double ,string> MulOutPutByTuple(double x)
        {
            double addResult = 0;
            var resultMessage = "";
            addResult = x + 8;
            resultMessage = "變量加了8之后的和為"+ addResult;
            return new Tuple<double, string>(addResult, resultMessage);

        }
    }
}
 static void Main(string[] args)
{

            MultipleOutPut output = new MultipleOutPut();
            double x = 5;
            var tupList=output.MulOutPutByTuple(x);
            Console.WriteLine("函數返回值:addResult={0},resultMessage={1}", tupList.Item1,tupList.Item2);
            Console.ReadLine();
}

  輸出結果如下:

  從上面輸出結果我們可以看到,函數返回了兩數相加之后的結果以及結果提示兩個信息。元組(Tuple)除了以上所述用途外,還有一個用途作者認為也非常有用,即用於單參數方法的多值傳遞(當函數參數僅是一個Object類型時,可以使用元組實現傳遞多個參數值),下面給出具體實例:

static void WriteStudentInfo(Object student)
{
    var studentInfo = student as Tuple<string,string, int, string>;
    Console.WriteLine($"Student Information: StudentCode[{studentInfo.Item1}], Name [{studentInfo.Item2}], Age[{studentInfo.Item3}],Sex[{studentInfo.Item4}]");
}

static void RunTest()
{
    var t = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(WriteStudentInfo));
    t.Start(new Tuple<string,string, int, string>("20200068","lilei", 20, ""));
    while (t.IsAlive)
    {
        System.Threading.Thread.Sleep(50);
    }
}

  Tuple元組的不足之處:

  • 問元素的時候只能通過ItemX去訪問,使用前需要明確元素順序,屬性名字沒有實際意義,不方便記憶;
  • 最多有八個元素,要想更多只能通過最后一個元素進行嵌套擴展
  • Tuple是一個引用類型,不像其它的簡單類型一樣是值類型,它在堆上分配空間,在CPU密集操作時可能有太多的創建和分配工作。

  鑒於以上的不足,C# 7.0中引入了一個新的ValueTuple(值元組)類型,園友北田在這篇(https://www.cnblogs.com/unity3ds/p/11641582.html)博文中對ValueTuple(值元組)進行了詳細的介紹,大家可以參考。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM