C#基础--函数编程

函数编程

本章主要讲解 C#7的新特性,比如本地函数、元组和模式匹配。

本地函数

本地函数在方法的作用域、属性访问器、构造函 数或者lambda表达式内声明。本地函数只能在包含成员的作用域内调用。可以使用本地函数,而不是使用仅一 个地方需要的私有方法。

private static void IntroWithLambdaExpression()
{
    Func<int, int, int> add = (x, y) =>
    {
        return x + y;
    };
    int result = add(37, 5);
    Console.WriteLine(result);
}

static void IntroWithLocalFunctions()
 {
     int add(int x, int y)
     {
         return x + y;
     }
     int result = add(37, 5);
     Console.WriteLine(result);
 }

 private static void IntroWithLocalFunctionsWithExpressionBodies()
 {
     int add(int x, int y) => x + y;

     int result = add(37, 5);
     Console.WriteLine(result);
 }

 private static void IntroWithLocalFunctionsWithClosures()
 {
     int z = 3;
     int result = add(37, 5);
     Console.WriteLine(result);

     int add(int x, int y) => x + y + z;
 }

递归本地函数

另一个使用本地函数的场景是递归调用,如下面使用Quicksort方法的示例所示。这里,本地函数Sort是
递归调用的,直到集合排好序为止

public static void QuickSort<T>(T[] elements) where T : IComparable<T>
{
    void Sort(int start, int end)
    {
        int i = start, j = end;
        var pivot = elements[(start + end) / 2];

        while (i <= j)
        {
            while (elements[i].CompareTo(pivot) < 0) i++;
            while (elements[j].CompareTo(pivot) > 0) j--;
            if (i <= j)
            {
                T tmp = elements[i];
                elements[i] = elements[j];
                elements[j] = tmp;
                i++;
                j--;
            }
        }
        if (start < j) Sort(start, j);
        if (i < end) Sort(i, end);
    }

    Sort(0, elements.Length - 1);
}

元组

元组能够组合不同类型的对象。使用数组可以组合相同类型的对象,而元组允许使用类型的不同组合。元 组有助于减少以下两个需求:

  • 定义自定义类或结构,以返回多个值
  • 定义参数,从方法中返回多个值

元组的声明和初始化

可以使用圆括号声明一个元组,并使用通过括号创建的元组字面量来初始化。

private static void IntroTuples()
{
    (string s, int i, Person p) t = ("magic", 42, new Person("Matthias", "Nagel"));
    Console.WriteLine($"s: {t.s}, i: {t.i}, p: {t.p}");

    var t2 = ("magic", 42, new Person("Matthias", "Nagel"));
    Console.WriteLine($"string: {t2.Item1}, int: {t2.Item2}, person: {t2.Item3}");

    var t3 = (s: "magic", i: 42, p: new Person("Matthias", "Nagel"));
    Console.WriteLine($"s: {t3.s}, i: {t3.i}, p: {t3.p}");

    (string astring, int anumber, Person aperson) t4 = t3;
    Console.WriteLine($"s: {t4.astring}, i: {t4.anumber}, p: {t4.aperson}");
}

元组解构

还可以将元组分解为变量。为此,只需要从前面的代码示例中删除元组变量,并在括号中定义变量名。然 后可以直接访问变量,其中包含元组部分的值

private static void TupleDeconstruction()
{
    (string s, int i, Person p) = ("magic", 42, new Person("Stephanie", "Nagel"));
    Console.WriteLine($"s: {s}, i: {i}, p: {p}");
    (var s1, var i1, var p1) = ("magic", 42, new Person("Stephanie", "Nagel"));
    Console.WriteLine($"s: {s1}, i: {i1}, p: {p1}");

    string s2;
    int i2;
    Person p2;
    (s2, i2, p2) = ("magic", 42, new Person("Katharina", "Nagel"));
    Console.WriteLine($"s: {s2}, i: {i2}, p: {p2}");

    (string s3, _, _) = ("magic", 42, new Person("Katharina", "Nagel"));
    Console.WriteLine(s3);
}

元组的返回

static (int result, int remainder) Divide(int dividend, int divisor)
{
    int result = dividend / divisor;
    int remainder = dividend % divisor;
    return (result, remainder);
}

模式匹配

从面向对象的观点来看,最好总是使用具体的类型和接口来解决问题。然而,通常这并不容易做到。在数 据库中,查询可能会给出与任何层次结构都无关的不同对象类型。访问API服务时,可以返回一个列表或对象, 或者可能什么也不返回。因此,方法通常应该与不同的类型一起工作。这就是模式匹配可以提供帮助的地方。

模式匹配与is运算符

与is运算符的简单匹配是const模式。在这个模式中,可以将对象与常量值进行比较

static void IsOperator(object item)
{
    // const pattern
    if (item is null)
    {
        Console.WriteLine("item is null");
    }

    if (item is 42)
    {
        Console.WriteLine("item is 42");
    }

    // type pattern
    if (item is int)
    {
        Console.WriteLine($"Item is of type int");
    }

    if (item is int i)
    {
        Console.WriteLine($"Item is of type int with a value {i}");
    }

    if (item is string s)
    {
        Console.WriteLine($"Item is a string: {s}");
    }

    if (item is Person p && p.FirstName.StartsWith("Ka"))
    {
        Console.WriteLine($"Item is a person: {p.FirstName} {p.LastName}");
    }

    if (item is IEnumerable<Person> people)
    {
        string names = string.Join(", ", people.Select(p1 => p1.FirstName).ToArray());
        Console.WriteLine($"it's a Person collection containing {names}");
    }

    // var pattern
    if (item is var every)
    {
        Console.WriteLine($"it's var of type {every?.GetType().Name ?? "null"} with the value {every ?? "nothing"}");
    }
}

模式匹配与switch语句

对于switch语句,也可以使用三种模式类型。

static void SwitchStatement(object item)
{
    switch (item)
    {
        case null:
        case 42:
            Console.WriteLine("it's a const pattern");
            break;
        case int i:
            Console.WriteLine($"it's a type pattern with int: {i}");
            break;
        case string s:
            Console.WriteLine($"it's a type pattern with string: {s}");
            break;
        case Person p when p.FirstName == "Katharina":
            Console.WriteLine($"type pattern match with Person and when clause: {p}");
            break;
        case Person p:
            Console.WriteLine($"type pattern match with Person: {p}");
            break;
        case var every:
            Console.WriteLine($"var pattern match: {every?.GetType().Name}");
            break;
        default:
    }
}

模式匹配与泛型

如果需要与泛型相匹配的模式,则需要将编译器配置为至少C# 7.1 C# 7.1为泛型添加了模式匹配。

public class HealthPackage
{
    public void CheckHealth()
    {
    }
}
public class HttpManager
{
    public void Send<T>(T package)
    {
        if (package is HealthPackage hp)
        {
            hp.CheckHealth();
        }
        //...
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sufengmarket

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值