C#核心知识回顾——12.lambda表达式、List排序、协变和逆变

1.Lambda表达式

可以将lambad表达式理解为匿名函数的简写
它除了写法不同外,使用上和匿名函数一模一样
都是和委托或者事件配合使用的

//匿名函数
//delegate(参数列表)
//{

//}

//lambda表达式
//(参数列表) =>
//{
      //函数体
//}

//1.无参无返回值
        Action a = () =>
        {
            Debug.Log("Lambda");
        };
        a();
        //2.有参
        Action<int> a2 = (int value) =>
        {
            Debug.Log("参数lambda");
        };
        a2(10);
        //3.参数类型可以省略,参数类型和委托或者事件一致
        Action<int> a3 = (value) =>
        {
            Debug.Log("无类型参数");
        };
        a3(100);
        //4.有返回值
        Func<string, int> a4 = (value) =>
        {
            Debug.Log("返回值");
            return 1;
        };
        a4("a");

闭包:

内层的函数可以引用包含在它外层的函数的变量
即使外层函数的执行已经终止

注意:
该变量提供的值并非变量创建时的值,而是在父函数范围内的最终值。

public class test : MonoBehaviour
{    
    
    private void Start()
    {
        Tes tes = new Tes();
        tes.DoThing();
    }

}

class Tes
{
    public event Action action;

    /// <summary>
    /// 这里就形成了闭包
    /// 当构造函数执行完毕,声明的临时变量value生命周期被改变了
    /// </summary>
    public Tes()
    {
        int value = 10;
        action = () =>
        {
            Debug.Log(value);
        };
        for (int i = 0; i < 5; i++)
        {
            //想要实现for循环存进事件不同的i值,需要在循环内部声明一个临时变量
            //每次存储的index不是同一个index
            int index = i;
            //假如事件注册进5个i变量,但是当使用时,变量的值都是for循环的最终值5,
            action += () =>
            {
                Debug.Log(index);
            };
        }
    }

    public void DoThing()
    {
        action();
    }
}

2.List排序

A.自带排序:

 //list自带排序
        List<int> list = new List<int>();
        list.Add(6);
        list.Add(1);
        list.Add(5);
        list.Add(3);
        list.Add(6);
        list.Add(5);

        list.Sort();

B.自定义排序:

public class test : MonoBehaviour
{

    private void Start()
    {
        List<Items> ite = new List<Items>();
        ite.Add(new Items(2));
        ite.Add(new Items(21));
        ite.Add(new Items(12));
        ite.Add(new Items(52));
        ite.Add(new Items(32));
        ite.Sort();
        for (int i = 0; i < ite.Count; i++)
        {
            Debug.Log(ite[i].id);
        }
    }

}
/// <summary>
/// 继承IComparable接口实现对比
/// </summary>
class Items : IComparable<Items>
{
    public int id;
    public Items(int id) { 
        this.id = id;
    }
    public int CompareTo(Items other)
    {
        //返回值的含义
        //小于0:
        //放在传入对象的前面
        //等于0:
        //保持当前的位置不变
        //大于0:
        //放在传入对象的后面
        //可以简单理解传入对象的位置就是
        //如果你的返回为负数就放在它的左边也就前面
        //如果你返回正数就放在它的右边也就是后面

        if (this.id < other.id)
        { 
            return -1; 
        }
        else
        {
            return 1;
        }
    }
}

C.通过委托函数实现排序

public class test : MonoBehaviour
{

    private void Start()
    {
        List<ShopItem> items = new List<ShopItem>();
        items.Add(new ShopItem(2));
        items.Add(new ShopItem(13));
        items.Add(new ShopItem(24));
        items.Add(new ShopItem(15));

        //1.调用函数
        items.Sort(SortShop);
        //2.匿名函数
        //items.Sort(delegate (ShopItem a, ShopItem b)
        //{
        //    if (a.id > b.id)
        //    {
        //        return 1;
        //    }
        //    else
        //    {
        //        return -1;
        //    }
        //});
        //3.lambda表达式
        //items.Sort((a, b) =>
        //{
        //    return a.id > b.id ? 1 : -1;
        //});

        for(int i = 0; i < items.Count; i++)
        {
            Debug.Log(items[i].id);
        }
    }

    static int SortShop(ShopItem a,ShopItem b)
    {
        //传入的两个对象,为列表中两个对象,进行两两比较
        //用左边的和右边的比较,负数在左边,正数在右边
        if (a.id > b.id)
        {
            return 1;
        }
        else
        {
            return -1;
        }
    }
}

class ShopItem
{
    public int id;
    public ShopItem(int id) 
    {
        this.id = id;
    }
}

public class test : MonoBehaviour
{

    private void Start()
    {
        List<ShopItem> items = new List<ShopItem>();
        items.Add(new ShopItem(1,2,3,4));
        items.Add(new ShopItem(4,3,2,1));
        items.Add(new ShopItem(6,7,8,9));
        items.Add(new ShopItem(9,8,7,6));
        items.Add(new ShopItem(3,4,5,6));

        int item = UnityEngine.Random.Range(0, 4);
        items.Sort((a, b) =>
        {
            int index = 0;
            switch (item)
            {
                case 0:
                    index = a.gong > b.gong ? 1 : -1;
                    break;
                case 1:
                    index = a.fang > b.fang ? 1 : -1;
                    break;
                case 2:
                    index = a.xue > b.xue ? 1 : -1;
                    break;
                case 3:
                    index = a.fan > b.fan ? 1 : -1;
                    break;
            }
            return index;
        });

        for (int i = 0; i < items.Count; i++)
        {
            switch (item)
            {
                case 0:
                    Debug.Log(items[i].gong);
                    break;
                case 1:
                    Debug.Log(items[i].fang);
                    break;
                case 2:
                    Debug.Log(items[i].xue);
                    break;
                case 3:
                    Debug.Log(items[i].fan);
                    break;
            }

        }
    }

}

class ShopItem
{
    public int gong;
    public int fang;
    public int xue;
    public int fan;
    public ShopItem(int gong,int fang,int xue,int fan) 
    {
        this.gong = gong;
        this.fang = fang;
        this.xue = xue;
        this.fan = fan;
    }
}

3.协变和逆变

协变:
和谐的变化,自然的变化
因为里氏替换原则 父类可以装子类
比如string变成object
感受是和谐的

逆变:
逆常规的变化,不正常的变化
因为里氏替换原则 父类可以装子类 但是子类不能装父类
所以比如object变成string
感受是不和谐的

协变和逆变是用来修饰泛型的
协变:out
逆变:in
用于在泛型中 修饰 泛型字母的
只有泛型接口和泛型委托能使用

//1.返回值和参数
//用out修饰的泛型只能作为返回值
delegate T Test out<out T>();
//用in修饰的泛型只能作为参数
delegate void Test In<in T>(T t);

public class test : MonoBehaviour
{
    //用out修饰的泛型只能作为返回值
    delegate T TestOut<out T>();
    //用in修饰的泛型只能作为参数
    delegate void TestIn<in T>(T t);
    private void Start()
    {
        //协变 父类总是能被子类替换
        TestOut<Son> os = () =>
        {
            return new Son();
        };
        TestOut<Father> of = os;
        //实际返回的是os里面装的函数 返回的是son
        Father f = of();

        //逆变
        TestIn<Father> iF = (value) =>
        {
        };
        TestIn<Son> iS = iF;
        //实际上 调用的是iF
        iS(new Son());
    }
}
class Father{}
class Son : Father{}

猜你喜欢

转载自blog.csdn.net/qq_29296473/article/details/131602315