简体   繁体   English

C#中的大小写/转换语句

[英]Case/Switch Statements in C#

I wanted to know if there's a way to declare a lot of case statements without having to write all of them. 我想知道是否有一种方法可以声明很多case语句而不必全部编写。 For example, my code: 例如,我的代码:

            switch (Weight)
            {
                case 0 to 2;
                    ShippingCost = "3.69";

                case 3 to 4;
                    ShippingCost = "4.86";

                case 5 to 6;
                    ShippingCost = "5.63";

                case 7 to 8;
                    ShippingCost = "5.98";

                case 9 to 10;
                    ShippingCost = "6.28";

                case 11 to 30;
                    ShippingCost = "15.72";

            }

I started converting VB to C# and realized that in order to have more than one case statements you have to declare them. 我开始将VB转换为C#,并意识到要拥有多个case语句,必须声明它们。 As you can see I have 11 to 30 and do not wanna have all those lines. 如您所见,我有11到30,并且不想拥有所有这些行。

You cannot use comparisons in C# as you can in VB. 您不能像在VB中那样在C#中使用比较。 You can however use fall-through cases, like so: 但是,您可以使用掉落情况,例如:

case 0:
case 1:
case 2:
  ShippingCost = "3.69";
  break;

case 3:
case 4:
  ShippingCost = "4.86";
  break;

Note that non-empty cases require either a throw , return or, break statement. 请注意,非空情况需要throwreturnbreak语句。 Also note that you can only fall-through on empty cases. 另请注意,您只能在空箱情况下失败。

Edit: 编辑:

For completeness, as others have pointed out, it is probably more sensible in this case to use a series of if statements, like so: 为完整性起见,正如其他人指出的那样,在这种情况下使用一系列if语句可能更明智,例如:

if(Weight<=2) {
  ShippingCost = "3.69";
}
else if(Weight <= 4) {
  ShippingCost = "4.86";
}
... etc

There is direct equivalent in C#, however, you can use fall-through so you don't have to repeat the implementation: 在C#中有直接等效项,但是,您可以使用穿透(fall-through),因此不必重复执行:

switch (Weight)
{
    case 0:
    case 1:
    case 2:
       ShippingCost = "3.69";
       break;
       ...

If statements would probably suit you much better in this scenario: 在这种情况下,如果语句可能更适合您:

if(Weight >= 0 && Weight <= 2){
    ShippingCost = "3.69";
} else if(Weight >= 3 && Weight <= 4){
    ShippingCost = "4.86";
}
...

Try like this: This solutions removes the need to write && in your else if statements 像这样尝试:此解决方案无需在else if语句中写&&

if(Weight >= 11 && Weight <= 30)
{
   ShippingCost = "15.72";
}
else if(Weight >= 9)
{
   ShippingCost = "6.28";
}
else if(Weight >= 7)
{
   ShippingCost = "5.98";
}
else if(Weight >= 5)
{
   ShippingCost = "5.63";
}
else if(Weight >= 3)
{
   ShippingCost = "4.86";
}
else if(Weight >= 0)
{
   ShippingCost = "3.69";
}

You could also write it as a Linq one liner: 您也可以将其编写为Linq one衬纸:

var ShippingCost = (new[] { new { w = 2, p = "3,69" }, 
                            new { w = 4, p = "4.86" }, 
                            new { w = 6, p = "5.63" }, 
                            new { w = 8, p = "5.98" }, 
                            new { w = 10, p = "6.28" }, 
                            new { w = 30, p = "15.72" }})
             .First(x => Weight <= x.w).p;

You would, as others have already stated, want to make sure that shipping for items weighing more than 30 is also handled correctly. 正如其他人已经指出的那样,您希望确保重量超过30的物品的运输也得到正确处理。

How bout just using this sort of approach 如何使用这种方法

private static double GetShippingCost(double weight)
{
    if (weight > 30) throw new ArgumentException("Weight over allowed maximum", "weight");

    if (weight <= 2) return 3.69;
    if (weight <= 4) return 4.86;
    if (weight <= 6) return 5.63;
    if (weight <= 8) return 5.98;
    if (weight <= 10) return 6.28;
    if (weight <= 30) return 15.72;

}

An alternative to using a case would be to write some kind of class to do the mapping, for example: 使用case的替代方法是编写某种类来进行映射,例如:

public sealed class CostsPerWeight
{
    class CostPerWeight
    {
        public int Low;
        public int High;
        public double Cost;
    }

    readonly List<CostPerWeight> costs = new List<CostPerWeight>();

    public CostsPerWeight Add(int low, int high, double result)
    {
        // Error handling omitted for brevity. 
        // Real code should check that low < high and that ranges do not overlap.

        costs.Add(new CostPerWeight { Low = low, High = high, Cost = result } );
        return this;
    }

    public double Cost(int weight)
    {
        // This throws if the weight isn't in the list.
        // If that's not what you want, you'd have to add extra error handling here.
        return costs.First(x => x.Low <= weight && weight <= x.High).Cost;
    }
}

Which you would use like this (I've used doubles instead of strings for the costs for this example, but you can use whatever type you need): 您将这样使用(在此示例中,我使用双精度代替字符串代替了字符串,但是您可以使用所需的任何类型):

var costs = new CostsPerWeight()
    .Add( 0,  2,  3.69)
    .Add( 3,  4,  4.86)
    .Add( 5,  6,  5.63)
    .Add( 7,  8,  5.98)
    .Add( 9, 10,  6.28)
    .Add(11, 30, 15.72);

double shippingCost = costs.Cost(weight);

If you have a lot of these switch statements in VB, it would be worth considering this approach. 如果VB中有很多这样的switch语句,那么值得考虑使用这种方法。

(The advantage of using this instead of a Linq one-liner is simply that it's easier to document and unit test. You could also create a CostsPerWeight class instance and pass it around - useful for decoupling code, dependency-injection and for unit testing.) (使用此代码而不是Linq单行代码的好处是,它更易于记录和进行单元测试。您还可以创建CostsPerWeight类实例并将其传递给CostsPerWeight -对于解耦代码,依赖性注入和单元测试非常有用。 )

It does seem to me that the concept of looking up a cost based on a weight is crying out to be encapsulated in a class, rather than embedded piecemeal in various parts of the code. 在我看来,基于权重查找成本的概念正在被要求封装在类中,而不是零碎地嵌入到代码的各个部分中。

Here's a more extended example of CostsPerWeight with more error handling: 这是CostsPerWeight扩展示例,具有更多错误处理:

public class CostsPerWeight
{
    class CostPerWeight
    {
        public int Low;
        public int High;
        public double Cost;
    }

    readonly List<CostPerWeight> costs = new List<CostPerWeight>();

    double min = double.MaxValue;
    double max = double.MinValue;
    double costForMin;

    public CostsPerWeight Add(int low, int high, double cost)
    {
        if (low > high)
            throw new ArgumentException(nameof(low) + " must be less than " + nameof(high));

        if (cost < 0)
            throw new ArgumentOutOfRangeException(nameof(cost), "cost must be greater than zero");

        costs.Add(new CostPerWeight { Low = low, High = high, Cost = cost } );

        if (low < min)
        {
            min = low;
            costForMin = cost;
        }

        if (high > max)
            max = high;

        return this;
    }

    public double Cost(int weight)
    {
        if (weight < min)
            return costForMin;

        if (weight > max)
            throw new InvalidOperationException($"Weight {weight} is out of range: Must be <= {max}");

        return costs.First(x => x.Low <= weight && weight <= x.High).Cost;
    }
}

The clearest way is to put your data into objects instead. 最清晰的方法是将数据放入对象中。

  private struct ShippingCost
  {
      public int MinWeight;
      public int MaxWeight;
      public decimal Cost;

      public ShippingCost(int min, int max, decimal cost)
      {
         MinWeight = min;
         MaxWeight = max;
         Cost = cost;
      }
  }

  private List<ShippingCost> Costs = new List<ShippingCost>
  {
      new ShippingCost(0, 2, 3.69m),
      new ShippingCost(3, 4, 4.86m),
      new ShippingCost(5, 6, 5.63m),
      new ShippingCost(7, 8, 5.98m),
      new ShippingCost(9, 10, 6.28m),
      new ShippingCost(11, 30, 15.72m),
  };

  // Choose shipping cost
  public decimal CalcShippingCost(int weight)
  {
      foreach (ShippingCost sc in Costs)
      {
          if (weight >= sc.MinWeight && weight <= sc.MaxWeight)
              return sc.Cost;
      }

      return 0.00m;     // default cost
  }

You can't do that in C#. 您无法在C#中做到这一点。 The best option if your max value for weight is 30 is to the use the default case. 如果您的体重最大值是30,最好的选择是使用默认情况。

Otherwise, if you don't want something like 否则,如果您不想要类似

case 11:
case 12:
case 13:
....
case 28:
case 29:
case 30:

an "oldschool" if/else if will be the the most readable solution “老式” if / else if将是最易读的解决方案

I'd recommend storing the data in a container and iterating through the container. 我建议将数据存储在容器中并遍历该容器。 You could create your own class or use a .net class like Tuple: 您可以创建自己的类或使用诸如Tuple的.net类:

var shippingCostsByWeight = new List<Tuple<int, int, string>>
{
    new Tuple<int, int, string>(0, 2, "3.69"),
    new Tuple<int, int, string>(3, 4, "4.86"),
    new Tuple<int, int, string>(5, 6, "5.63"),
    new Tuple<int, int, string>(7, 8, "5.98"),
    new Tuple<int, int, string>(9, 10, "6.28"),
    new Tuple<int, int, string>(11, 30, "15.72"),
};

ShippingCost = shippingCostsByWeight
                .First(tuple => weight >= tuple.Item1 && weight <= tuple.Item2).Item3;

You could use a fall-through case switch statement, which goes as the following: 您可以使用以下情况切换语句:

case 0:
case 1:
case 2:
  shippingCost = "3.69";
  break;

... and so on

Which will cause 0 to set shippingCost to 3.69 aswell as 1 and 2. :) 这将导致0将shippingCost设置为3.69以及1和2。:)
That would be my Solution to this 那就是我的解决方案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM