如何减少if-else的使用

  If-else一时爽,代码维护火葬场。或者if-else的套娃全都令人崩溃,如何减少if-else的使用呢?在cpp中,可以使用map+lambda的方法进行,而在C#中,switch提供了更强的功能,比C++酷多了:)

1. C++的map+lambda

  C中Map其实就是其他数据结构中的字典,在C里面如果一些内容不能使用switch的话,则可以使用Map+lambda的方法:
  首先看一下cpp关于switch的文档,截止到C++17标准,switch仍只支持几种简单的类型,支持类型为整形,枚举以及可以隐式转换成整形的类型,那么很明显std::string类型是不支持switch的,那么如果相对输入string的不同做一些不同的事情,那么就可以使用Map+lambda进行操作。

  Any expression of integral or enumeration type, or of a class type contextually implicitly convertible to an integral or enumeration type, or a declaration of a single non-array variable of such type with a brace-or-equals initializer.

1.1 模拟命令行

  假设现在我想要模拟一些终端命令,那么我要怎么实现?首先一个循环用于循环侦听输入,然后根据输入的消息进行处理。那么不同情况的输入对应情况要怎么写的?if-else可以使用,但说实话写多了就不清晰,可以考虑使用map+lambda进行操作:

#include<iostream>
#include"FileSystem.h"
#include<sstream>
#include<functional>
#include<map>
using namespace std;
int main() {
    //自定义的类,定义了一系列的操作
	FileSystem f{};
	string str;
	vector<string> vec;

	map<string, function<void(vector<string>)>> map;

    //emplace直接调用构造函数添加,括号内为引用捕获以便使用自定义对象f
	map.emplace("cd", [&f](vector<string> vec)->void {f.MoveIn(vec[0]); });
	map.emplace("ls", [&f](vector<string> vec)->void {f.ShowDetails(); });
	map.emplace("rm-fl", [&f](vector<string> vec)->void {f.DeleteFile(vec[0]); });
	map.emplace("rm-fo", [&f](vector<string> vec)->void {f.DeleteFolder(vec[0]); });
	map.emplace("rename", [&f](vector<string> vec)->void {f.ChangeName(vec[0],vec[1]); });
	map.emplace("ls-a", [&f](vector<string> vec)->void {f.ShowAll(); });
	map.emplace("mkdir", [&f](vector<string> vec)->void {f.NewFolder(vec[0]); });
	map.emplace("newfile", [&f](vector<string> vec)->void {f.NewFile(vec[0]); });

	f.CurrentPath();
	while (getline(cin,str,'\n'))
	{
		vec.clear();
		try {
			stringstream ss(str);
			while (getline(ss, str, ' '))
			{
				vec.push_back(str);
			}
			auto choice = vec[0];
			vec.erase(vec.begin());
			map[choice](vec);
			f.CurrentPath();
		}
		catch (exception) {
			cout << "Invaild input!" << endl;
			f.CurrentPath();
		}

	}
}

2. C#的if-else

  当我们看向C#的switch的时候,情况就好起来了,C#的switch提供的功能极其强大,当然很多功能离不开反射(C认为你不需要为你可能用不到的东西买单,所以不提供元数据的C自然不提供反射功能),给予了更强的空间与方法。详细了解C#8.0的switch.

2.1 重写1.1中的内容

  当你使用C#完成这项任务的时候,使用dictionary+action就并不是一个明智的选择了,switch为我们提供了更强大的功能,你只需要为特定的string实现自己的逻辑即可。

2.2 switch+when以及对类型的筛选

  这里就是switch的强大之处了,拥有非常高的自由度。不仅可以在里面添加一些筛选条件,也可以对类型进行一些筛选。下面的实例代码是微软文档提供的:

using System;

public abstract class Shape
{
   public abstract double Area { get; }
   public abstract double Circumference { get; }
}

public class Rectangle : Shape
{
   public Rectangle(double length, double width)
   {
      Length = length;
      Width = width;
   }

   public double Length { get; set; }
   public double Width { get; set; }

   public override double Area
   {
      get { return Math.Round(Length * Width,2); }
   }

   public override double Circumference
   {
      get { return (Length + Width) * 2; }
   }
}

public class Square : Rectangle
{
   public Square(double side) : base(side, side)
   {
      Side = side;
   }

   public double Side { get; set; }
}

public class Circle : Shape
{
   public Circle(double radius)
   {
      Radius = radius;
   }

   public double Radius { get; set; }

   public override double Circumference
   {
      get { return 2 * Math.PI * Radius; }
   }

   public override double Area
   {
      get { return Math.PI * Math.Pow(Radius, 2); }
   }
}

public class Example
{
   public static void Main()
   {
      Shape sh = null;
      Shape[] shapes = { new Square(10), new Rectangle(5, 7),
                         sh, new Square(0), new Rectangle(8, 8),
                         new Circle(3) };
      foreach (var shape in shapes)
         ShowShapeInfo(shape);
   }

   private static void ShowShapeInfo(Shape sh)
   {
      switch (sh)
      {
         // Note that this code never evaluates to true.
         case Shape shape when shape == null:
            Console.WriteLine($"An uninitialized shape (shape == null)");
            break;
         case null:
            Console.WriteLine($"An uninitialized shape");
            break;
         case Shape shape when sh.Area == 0:
            Console.WriteLine($"The shape: {sh.GetType().Name} with no dimensions");
            break;
         case Square sq when sh.Area > 0:
            Console.WriteLine("Information about square:");
            Console.WriteLine($"   Length of a side: {sq.Side}");
            Console.WriteLine($"   Area: {sq.Area}");
            break;
         case Rectangle r when r.Length == r.Width && r.Area > 0:
            Console.WriteLine("Information about square rectangle:");
            Console.WriteLine($"   Length of a side: {r.Length}");
            Console.WriteLine($"   Area: {r.Area}");
            break;
         case Rectangle r when sh.Area > 0:
            Console.WriteLine("Information about rectangle:");
            Console.WriteLine($"   Dimensions: {r.Length} x {r.Width}");
            Console.WriteLine($"   Area: {r.Area}");
            break;
         case Shape shape when sh != null:
            Console.WriteLine($"A {sh.GetType().Name} shape");
            break;
         default:
            Console.WriteLine($"The {nameof(sh)} variable does not represent a Shape.");
            break;
      }
   }
}
// The example displays the following output:
//       Information about square:
//          Length of a side: 10
//          Area: 100
//       Information about rectangle:
//          Dimensions: 5 x 7
//          Area: 35
//       An uninitialized shape
//       The shape: Square with no dimensions
//       Information about square rectangle:
//          Length of a side: 8
//          Area: 64
//       A Circle shape

本文章使用limfx的vsocde插件快速发布