如何从C#(ASP.NET)中的函数返回多个值?

时间:2010-10-02 13:04:40

标签: c#

我有一个页面,其中包含用户输入数字的某些产品和文本字段。我首先使用JavaScript来计算总成本。根据他们输入的用户数量,他们获得不同的费率(如下面的代码所示)。当用户在文本字段中键入或粘贴数字时,将调用函数CalculateCost调用其他函数(仅在示例中显示两个函数,CDCOst和DVDCost),以确保每月成本和年度成本字段显示正确的值。

我当然希望在插入数据库之前在后面的代码中进行最终计算。如何在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?
    }


}

9 个答案:

答案 0 :(得分:8)

使用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,
        };
}

答案 1 :(得分:2)

.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 :(得分:0)

您可以使用输出参数来返回多个值

OR

您可以返回一个集合(例如双数组)或自定义对象,其中包含您要返回的所有对象。

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

答案 3 :(得分:0)

您可以使用数组,如下所示:

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

然后像这样使用它:

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

答案 4 :(得分:0)

现在改变你现在的方式,返回一个CDCost对象:

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

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

但是如果你对c#语法感兴趣 - 例如你可以使用outarray(虽然我认为在这种情况下它们都是糟糕的设计)。

答案 5 :(得分:0)

在技术上,有点聪明的意义上,答案是你不能从函数中返回多个值。函数返回一个值或不返回任何值。这适用于你的Javascript示例 - 它实际上并没有返回两个值,而是返回一个值,这是一个包含两个元素的数组。

那就是说,正如其他人已经指出的那样,这是你的选择:

1)返回一个数组。这就是你在Javascript示例中所做的,它也适用于其他任何地方。我看到的问题有两个:一,你只限于一种类型(如果适用的话,它的子类型)。如果你想返回一个double和一个字符串,你需要让它返回一个Objects数组并转换为适当的类型。第二,它是一个相当难以使​​用的API,因为排序是至关重要的。任何使用你的函数的代码都需要知道returnValue [0]表示,例如,月度金额和returnValue [1]代表年度金额。当然,你可以在文档中说,但它仍然是一个棘手的API使用。如果你(或其他人)由于某种原因(可能是粗心大意)改变了返回值的顺序,上帝会帮助你。这将是一个可怕的错误追踪。

2)返回字典。这避免了排序问题,但它通过添加密钥问题弥补了这一点 - 任何使用您的代码的人都需要知道返回的字典使用了一些特定的密钥集(例如,“monthlyAmount”和“annualAmount”)。无论是消费代码还是方法体内的拼写错误,都会让人痛苦不堪。就像阵列解决方案一样,您必须确保记录关键值。它也遇到阵列解决方案带来的相同类型问题。它可能也会比阵列解决方案的性能稍差,尽管它是否真的会产生明显的差异是值得怀疑的。

3)out参数。这避免了以前的问题,因为它们可以是任何类型,并且编译器/ IDE将捕获任何拼写错误/错误分配。但是,一般来说,我试图避免输出参数(FxCop也是如此)。就个人而言,他们似乎滥用参数语法 - 参数用于将数据传递到函数中,而out参数虽然在技术上这样做,却被用于返回值而不是函数使用的值。它还污染方法签名 - 它需要传递更多参数n,如果你想要一堆重载(并且你没有使用.NET 4.0的可选/命名参数),这尤其令人讨厌。更简单的说,在返回值之前必须声明返回值有点烦人,即

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

4)返回自定义类的实例。添加一个专门用于单个方法的返回值的整个类有点难看,但这可能是最优雅的解决方案,因为它告诉人们使用该方法确切地返回了什么,并且你可以混合类型(并且方法没有'为了能够返回内容,我必须采取额外的参数,就像使用out参数一样,这使得方法调用更加清晰)。但是,我不会过分夸大 - 如果你发现自己有很多方法需要返回多个(非常不同的)值(你不应该这样找到自己),那么为每个方法添加一个新的返回类我想,会让你的生活变得更加邪恶。

5)不返回多个值。这可能并不总是一个选项,但是如果你发现自己想要返回多个值,我会很难看出值是否需要一起返回,或者你是否可以将它分成两个调用(GetMonthlyAmount()和GetAnnualAmount( ), 例如)。有时候这没有意义,特别是如果你的方法做了一些昂贵的事情,如进行数据库调用。

tl; dr:当您想要返回多个值时,首先要确保不能将其拆分为单独的方法,然后再将其拆分为自定义返回类。在合理范围内。

答案 6 :(得分:0)

我知道这个帖子已经老了,但我以为我会增加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

答案 7 :(得分:0)

我会说命名的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();
    

答案 8 :(得分:-1)

执行此操作的最佳方法是返回值为

的字典
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
    }

}