委托

定义委托

关键字:delegate(自定义委托),Action(无返回值委托),Func(有返回值委托)
跟类(class)是平行的关系,不过也可以声明在类中,不过尽量不要声明在类中,委托是方法的类型,委托可以有参数可以有返回类型,但必须与所赋值的方法一致

  1. D1 d1 = F1;//将d1委托指向F1方法
  2. d1();//调用d1指向的方法
  3. d1 = F2;//
  4. d1();//将d1委托指向F2方法
  5. D2 d2 = Add;
  6. d2(1,2);
  7. void F1()
  8. {
  9. Console.WriteLine("我是F1");
  10. }
  11. void F2()
  12. {
  13. Console.WriteLine("我是F2");
  14. }
  15. int Add(int i1,int i2)
  16. {
  17. return i1+i2;
  18. }
  19. delegate void D1();//声明无参数,返回值是void的委托D1
  20. delegate int D2(int i1,int i2);//声明有参数有返回值的委托D2

一般情况下不会自定义泛型,而是利用微软自带的Action或Func来定义泛型,其中,Func定义委托时,最后一个参数为返回类型,后方的则是形参的类型,如下方的例子Func,最后一个string是返回类型,前方两个int是形参i1与i2的类型。

Action d1 = F1;
d1();
d1 = F2;
d1();

Func<int,int,string> d2 = Add;
Console.WriteLine(d2(5,6));

void F1()
{ 
    Console.WriteLine("我是F1");
}

void F2()
{
    Console.WriteLine("我是F2");
}

string Add(int i1,int i2)
{
    return (i1+i2).ToString();
}

匿名方法

指的是没有名字的方法,

Action d1 = delegate ()
{
    Console.WriteLine("我是匿名方法");
};
d1();

Action<string,int> d2 = delegate (string x, int y)
{
    Console.WriteLine($"字符串{x}与整型{y}");
};
d2("字符串",50);

Func<int, int, int> d3 = delegate (int a, int b)
{
    return a + b;
};
Console.WriteLine(d3(5,6));

Lambda

Func<int, int, int> d4 = (int a, int b) =>
{
    return a + b;
};
Console.WriteLine(d4(9, 6));

//也可以不写参数类型,编译器会自动判断参数类型
Func<int, int, int> d5 = (a, b) =>
{
    return a + b;
};
Console.WriteLine(d5(9, 6));

//无返回值只有一行代码,可以省略{}
Action d11 = () => Console.WriteLine("我是lambda");
d11();
Action<string> d12 = (ddd) => Console.WriteLine(ddd);
d12("我是lambda2");

//有返回值,只有一行代码,可以省略return与{},return与{}必须同时省略
Func<string, string> d13 = (ddd) => $"我是有返回值有参数{ddd}";
Console.WriteLine(d13("lambda"));

//如果只有一个参数,()也可以省略
Func<string,string> d14 = ddd => $"我是有返回值有参数且只有一个参数的{ddd}";
Console.WriteLine(d14("lambda"));

LINQ

自己写一个Where方法

例子中,要查找出ints数组中符合条件的数据,调用方法直接传入数组与委托达到效果

int[] ints = new int[] { 10,20,30,1,2,5,6,99,8,10,3};
var ddd = MyWhere2(ints,b => b>10);
foreach (var i in ddd)
{ 
    Console.WriteLine(i);
}


IEnumerable<int> MyWhere1(IEnumerable<int> a, Func<int, bool> b)
{
    List<int> intlist = new List<int>();
    foreach (int i in a)
    {
        if (b(i))
            intlist.Add(i);
    }
    return intlist;
}

//简化版本
IEnumerable<int> MyWhere2(IEnumerable<int> a,Func<int,bool> b)
{
    foreach (int i in a)
    {
        if(b(i))
            yield return i;
    }
}

常用扩展方法

List<Employee> lis = new List<Employee>();
lis.Add(new Employee { Id = 1, Name = "jerry", Age = 28, Gender = true, Salary = 5000 });
lis.Add(new Employee { Id = 2, Name = "jim", Age = 33, Gender = true, Salary = 3000 });
lis.Add(new Employee { Id = 3, Name = "lily", Age = 35, Gender = false, Salary = 9000 });
lis.Add(new Employee { Id = 4, Name = "lucy", Age = 16, Gender = false, Salary = 2000 });
lis.Add(new Employee { Id = 5, Name = "kimi", Age = 25, Gender = true, Salary = 1000 });
lis.Add(new Employee { Id = 6, Name = "nancy", Age = 33, Gender = false, Salary = 8000 });
lis.Add(new Employee { Id = 7, Name = "zack", Age = 31, Gender = true, Salary = 8500 });
lis.Add(new Employee { Id = 8, Name = "jack", Age = 38, Gender = true, Salary = 8000 });

class Employee
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public int Age { get; set; }
    public bool Gender { get; set; }
    public int Salary { get; set; }
    public override string ToString()
    {
        return
            $"Id={Id},Name={Name},Age={Age},Gender={Gender},Salary={Salary}";
    }
}

Where

查询(取出)符合条件的结果,返回的是集合IEnumerable,如下方例子,查询出年龄大于30的数据并打印

IEnumerable<Employee> items1 = lis.Where(e=>e.Age >30);
foreach (var ddd in items1)
{
    Console.WriteLine(ddd);
}

Count

注意区别Count属性与Count()方法,统计数据的条数,也可以输入条件统计符合条件的数据条数,返回的是行数int
如果查询的数据行数较多,超过了int类型的最大值,可以使用LongCount方法,这样返回值就会是long类型,LongCount与Count使用方法一样

lis.Count();//统计总数据行数
lis.Count(e=>e.Salary <5000);//统计工资小于5000的数据行数
Console.WriteLine(lis.Count(e=>e.Salary <5000 && e.Gender == true));//可以写的更复杂
lis.LongCount(e=>e.Age>10);

Any

判断集合中是否至少有一条数据满足要求,如果没有传入参数,则只判断集合是否至少有一条数据,返回的是bool类型的数据,与Count相比,Any是查找到一条符合条件的数据就返回了,Count则会遍历所有的数据,所以在只需要判断是否至少有一条数据符合条件时,用Any效率会更高

lis.Any();//判断集合是否至少有一条数据
lis.Any(e=> e.Salary>10000);//判断是否至少有一条数据工资大于10000

获取一条数据

  • Single:如果确认有且只有一条满足要求的数据,那么就用Single方法。如果没有满足条件的数据或者满足条件的数据多与一条,Single方法就会抛出异常,有且只有一条的话,就会返回该条符合条件的数据,返回的是IEnumerable类型的数据。
  • SingleOrDefault:用法与Single类似,如果数据多于一条,就会抛出异常,不同的是,如果少于一条,就会返回类型的默认值。
  • First:如果满足条件的数据有一条或多条,First方法就会返回第一条数据,如果没有满足条件的数据,就会抛出异常。
  • FirstOrDefault:用法与First方法类似,不同的是,如果没有满足条件的数据,就会返回类型的默认值。 ```csharp lis.Single(e=>e.Name == “jerry”);//获取姓名等于jerry的数据

int[] ddd = new int[] { 1, 2, 3, 4, 5, 6 }; int dd = ddd.SingleOrDefault(e=>e >10);//返回int的默认值0

lis.First(e=> e.Age>30);//查询第一条年龄大于30的数据

Console.WriteLine(lis.FirstOrDefault(e=> e.Age>90));//返回默认值 ```