簡體   English   中英

如何從 C# (ASP.NET) 中的函數返回多個值?

[英]How to return multiple values from a function in C# (ASP.NET)?

我有一個頁面,其中有一些產品和用戶輸入數字的文本字段。 我首先使用 JavaScript 來計算總成本。 根據他們輸入的用戶數量,他們獲得不同的費率(如下面的代碼所示)。 當用戶在文本字段中鍵入或粘貼數字時,會調用CalculateCost 函數,該函數調用其他函數(示例中僅顯示兩個,CDCOst 和DVDCost)以確保字段Monthly Cost 和Annual Cost 顯示正確的值。

我當然想在插入數據庫之前在后面的代碼中進行最終計算。 我怎樣才能在 C# 中實現類似的東西?

function CDCost() {
                var monthlyAmount;
                var annualAmount;
                var amount;
                var users = $('#txtCD').val();

            if (users > 0 && users < 100) {
                amount = users * 14.95;
                monthlyAmount = amount;
                annualAmount = monthlyAmount * 12;
                return [monthlyAmount, annualAmount];
            }
            if (users >= 100 && users <= 250) {
                amount = users * 12.95;
                monthlyAmount = amount;
                annualAmount = monthlyAmount * 12;
                return [monthlyAmount, annualAmount];
            }
            if (users == 0) {
                monthlyAmount = 0;
                annualAmount = 0;
                return [monthlyAmount, annualAmount];
            }
        }

function DVDCost() {
                var monthlyAmount;
                var annualAmount;
                var amount;
                var users = $('#txtDVD').val();

            if (users > 0 && users < 100) {
                amount = users * 16.95;
                monthlyAmount = amount;
                annualAmount = monthlyAmount * 12;
                return [monthlyAmount, annualAmount];
            }
            if (users >= 100 && users <= 250) {
                amount = users * 14.95;
                monthlyAmount = amount;
                annualAmount = monthlyAmount * 12;
                return [monthlyAmount, annualAmount];
            }
            if (users == 0) {
                monthlyAmount = 0;
                annualAmount = 0;
                return [monthlyAmount, annualAmount];
            }
        }


        function CalculateCost() {
            var cd = CDCost();
            var dvd = DVDCost();

            var monthlyCost = cd[0] + dvd[0];
            var annualCost = cd[1] + dvd[1];

            return [monthlyCost, annualCost];
        }

        $('#txtCD').bind('keyup change', function (ev) {
            var cost = CalculateCost();
            var monthly = cost[0];
            var annual = cost[1];

            $('#MonthlyCostSum').text(monthly);
            $('#AnnualCostSum').text(annual)
        });

我將如何在 C# 中繼續這樣做?

類似的東西:

protected double CDCost()
    {
        double monthlyAmount;
        double annualAmount;
        double amount;
        double users = Convert.ToDouble(txtCD.Text);

        if (users > 0 && users < 100)
    {
        amount = users * 14.95;
        monthlyAmount = amount;
        annualAmount = monthlyAmount * 12;
        return //how do I return the values here to a CalculateCost function?
    }


}

要么使用out參數,要么創建一個新類型來包裝您想要返回的所有內容(所謂的“屬性包”):

class ReportData
{
    public double MonthlyAmount { get; set; }
    public double AnnualAmount { get; set; }
    public double Amount { get; set; }
}

...

protected ReportData CDCost()
{
    return new ReportData() 
        { 
            Amount = users * 14.95
            MonthlyAmount = amount, 
            AnnualAmount = amount * 12.0,
        };
}

.NET 4 中的元組類完美地完成了這項工作。

protected Tuple<double, double, double, double> CDCost()
    {
        double monthlyAmount;
        double annualAmount;
        double amount;
        double users = Convert.ToDouble(txtCD.Text);
   if (users > 0 && users < 100)
    {
        amount = users * 14.95;
        monthlyAmount = amount;
        annualAmount = monthlyAmount * 12;
        return //how do I return the values here to a CalculateCost function?
    }
    return new Tuple<double, double, double, double>(monthlyAmount, annualAmount, amount, users);
}

我知道這個線程很舊,但只是想我會添加我的 2 美分:包含該函數的同一個類中的一些只讀類屬性怎么樣(此時可以變成 Sub )? 這對我來說是最干凈的解決方案。

在VB中:

Private iAmount  As Integer
Public ReadOnly Property Amount() As Integer
    Get
        Return iAmount
    End Get
End Property

Private iMonthlyAmount  As Integer
Public ReadOnly Property MonthlyAmount() As Integer
    Get
        Return iMonthlyAmount
    End Get
End Property

Private iAnnualAmount  As Integer
Public ReadOnly Property AnnualAmount() As Integer
    Get
        Return iAnnualAmount
    End Get
End Property

您可以使用 out 參數返回多個值

您可以返回一個集合(例如雙數組)或自定義對象,其中包含您要返回的所有對象。

class MyCustomType
{
  double AnnualAmount{get; set;}
  double MonthlyAmount{get; set;}
}

// and in your function you could go
return new MyCustomType{ AnnualAmount = 4.5d, MonthlyAmount = 5.5d  };

您可以使用數組,如下所示:

protected double[] CDCost() {
    //a lot of code
    return new double[2] { annualAmount, monthlyAmount };
}

然后像這樣使用它:

double cdCost = CDCost();
annualAmount = cdCost[0];
monthlyAmount = cdCost[1];

會改變你現在做的方式,返回一個 CDCoost 對象:

public Class CDCost
{
  public double Monthly {get;set;}
  public double Annually {get return Monthly*12;}  

  public CDCost(double monthly)
  {
    Monthly=monthly;
  }
}

但是,如果您對 c# 語法感興趣 - 例如,您可以使用outarray (盡管我認為在這種情況下它們兩者都是糟糕的設計)。

從技術上來說,有點聰明,答案是你不能從一個函數中返回一個以上的值。 一個函數要么返回一個值,要么不返回任何值。 這適用於您的 Javascript 示例——它實際上並沒有返回兩個值,而是返回一個值,它是一個包含兩個元素的數組。

也就是說,正如其他人已經指出的那樣,這是您的選擇:

1) 返回一個數組。 這就是您在 Javascript 示例中所做的,它也適用於其他任何地方。 我看到的問題有兩個:一,你僅限於一種類型(以及,如果適用,它的子類型)。 如果你想返回一個雙精度值和一個字符串,你需要讓它返回一個對象數組並轉換為適當的類型。 第二,它使得 API 相當難以使​​用,因為排序至關重要。 任何使用您的函數的代碼都需要知道 returnValue[0] 代表每月金額,而 returnValue[1] 代表年度金額。 當然,您可以在文檔中這么說,但它仍然是一個使用起來很棘手的 API。 如果您(或其他人)出於某種原因(可能是粗心大意)更改了返回值的順序,上帝會幫助您。 這將是一個可怕的錯誤追蹤。

2) 返回字典。 這避免了排序問題,但它通過添加關鍵問題來彌補這一點——使用您的代碼的任何人都需要知道返回的字典使用了一些特定的鍵集(例如,“monthlyAmount”和“annualAmount”)。 無論是在使用代碼中還是在方法體中,打字錯誤都會讓人頭疼。 就像數組解決方案一樣,您必須確保記錄鍵值。 它還存在與陣列解決方案相同的類型問題。 它也可能比陣列解決方案的性能稍差,盡管它是否真的會產生顯着的差異是值得懷疑的。

3) out參數。 這避免了之前的問題,因為它們每個都可以是任何類型,並且編譯器/IDE 將捕獲任何拼寫錯誤/錯誤分配。 但是,通常我會盡量避免使用 out 參數(就像FxCop 一樣)。 就個人而言,他們似乎在濫用參數語法——參數用於將數據傳遞到函數中,而參數用於將數據傳遞到函數中,而從技術上講,它們確實是這樣做的,用於返回值而不是函數要使用的值。 它還污染方法簽名-這是n你需要傳遞,這是如果你想了一堆重載特別煩多個參數(和你沒有使用.NET 4.0的可選/命名參數)。 在一個更次要的注意事項中,必須在返回值之前聲明返回值有點煩人,即

double outparam1, outparam2;
SomeFunction(out outparam1, out outparam2);
//use out parameters

4) 返回自定義類的實例。 專門為單個方法的返回值添加整個類有點難看,但這可能是最優雅的解決方案,因為它告訴人們使用該方法的確切返回值,並且您可以混合類型(並且該方法不會t 必須采用額外的參數才能返回內容,就像使用out參數一樣,這使得方法調用更清晰)。 但是,我不會過度使用這個——如果你發現自己有很多方法需要返回多個(非常不同的)值(你不應該以這種方式發現自己),然后為每個方法添加一個新的返回類我想,會讓你的生活變得更加地獄般。

5) 不返回多個值。 這可能並不總是一個選項,但如果您發現自己想要返回多個值,我會仔細考慮是否需要將這些值一起返回,或者是否可以將其拆分為兩個調用(GetMonthlyAmount() 和 GetAnnualAmount() ),例如)。 有時這沒有意義,特別是如果您的方法執行昂貴的操作,例如進行數據庫調用。

tl;dr:當你想返回多個值時,首先確保你不能將它拆分成單獨的方法,然后是自定義返回類。 情理之中。

我會說命名的 touple 是一種新的方式(顯然是從 C#7 開始)

protected (double amount, double monthlyAmount, double annualAmount) CDCost()
    {
        double monthlyAmount;
        double annualAmount;
        double amount;
        double users = Convert.ToDouble(txtCD.Text);

        if (users > 0 && users < 100)
        {
            amount = users * 14.95;
            monthlyAmount = amount;
            annualAmount = monthlyAmount * 12;
            return (amount, monthlyAmount, annualAmount);
        }
        throw new NotImplementedException();
    }

然后你可以使用析構函數隱式調用它

    var (amount, monthlyAmount, annualAmount) = CDCost();
    

最好的方法是返回一個包含值的字典

protected Dictionary<string, double> CDCost()
    {
        Dictionary<string,double> values = new Dictionary<string,double>();
        double monthlyAmount;
        double annualAmount;
        double amount;
        double users = Convert.ToDouble(txtCD.Text);

        if (users > 0 && users < 100)
    {
        amount = users * 14.95;
        values["monthlyAmount"] = amount;
        values["annualAmount"] = monthlyAmount * 12;
        return values
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM