协变和逆变随笔

Posted morec

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了协变和逆变随笔相关的知识,希望对你有一定的参考价值。

当使用委托时,一般会出现两种角色:广播者(broadcaster)和订阅者(subscriber)。
广播者是包含委托字段的类型,它通过调用委托决定何时进行广播。
而订阅者是方法的目标接收者。订阅者通过在广播者的委托上调用+=和-=来决定何时开始监听而何时监听结束。订阅者不知道也不会干涉其他的订阅者。
而事件就是正式定义这一模式的语言功能。事件是一种使用有限的委托功能实现广播者/订阅者模型的结构。使用事件的主要目的在于保证订阅者之间不互相影响。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DelegateDemo
{
    class Program
    {
        public delegate void ProgressReporter(int percentComplete);
        static void Main(string[] args)
        {
            {
                //X x = new X();
                //ProgressReporter p = x.InstanceProcess;
                //p(99);
                //Console.WriteLine(p.Target == x);
                //Console.WriteLine(p.Method);

                //ProgressReporter pt = StaticProcess;
                //pt(100);
                //Console.WriteLine(pt.Target);
                //Console.WriteLine(pt.Method);
            }
            {
                //int[] values = { 1, 2, 3 };
                //Util.Transform(values, Square);
                //foreach (var item in values)
                //{
                //    Console.Write(item + " ");
                //}
            }
            {
                //适用于引用类型的接口
                //逆变 协变   逆变可以参考一个词语逆子,故逆变是子=>基, 协变是基 => 子(更具体的类型)
                //协变 用关键字 out 输出  就是可以输出子类   
                //逆变 用关键字 in 输入  就是输入参数可以是基类
                //例子 interface ITestOut<out T>{ T Method();}
                //例子 interface ITestIn<in <T>{ void Method(T obj);}
                //事件  事件是一种使用有限的委托功能实现广播着/订阅者模型的结构,使用事件的主要目的在于保证订阅者之间不互相影响
                //int[] collection = { 4, 5, 6 };
                //UtilForItrans.TransformAll(collection, new Squarer());
                //foreach (var item in collection)
                //{
                //    Console.Write(item + " ");
                //}
            }
            {
                //StringAction sa = new StringAction(ActOnObject);
                //sa("hello");
                //ObjectRetriever or = new ObjectRetriever(RetrieveString);
                //Console.WriteLine(or());
            }
            Console.Read();

        }
        delegate object ObjectRetriever();
        delegate void StringAction(string s);
        private static void ActOnObject(object o) => Console.WriteLine(o);
        private static int Square(int arg) => arg * arg;
        static string RetrieveString() => "Hello";
        static void StaticProcess(int percentComplete)
        {
            Console.WriteLine(percentComplete);
        }
    }

    class X
    {
        public void InstanceProcess(int percentComplete)
        {
            Console.WriteLine(percentComplete);
        }
    }
    public delegate T Transformer<T>(T arg);
    public class Util
    {
        public static void Transform<T>(T[] values,Transformer<T> t)
        {
            for (int i = 0; i < values.Length; i++)
            {
                values[i] = t(values[i]);
            }
        }
    }

    public interface ITransformer
    {
        int Transform(int x);
    }

    public class UtilForItrans
    {
        public static void TransformAll(int[] values,ITransformer t)
        {
            for(int i = 0; i < values.Length; i++)
            {
                values[i] = t.Transform(values[i]);
            }
        }
    }

    class Squarer : ITransformer
    {
        public int Transform(int x) => x * x;
    }

    class Broadcaster
    {
         PriceChangedHandler priceChanged;
        public event PriceChangedHandler PriceChanged {
            add { priceChanged += value; }
            remove { priceChanged -= value; }
        }
    }
    public delegate void PriceChangedHandler(decimal oldPrice, decimal newPrice);

    //如果去掉event,不会影响运行结果,但是影响如下:
    //通过重新指派PriceChanged替换其他的订阅者(不用+=运算符)
    //清楚所有的订阅者(将PriceChanged设置位null)
    //通过调用其委托广播到其他的订阅者
    public class Stock
    {
        string symbol;
        decimal price;
        public Stock(string symbol)
        {
            this.symbol = symbol;
        }

        public event PriceChangedHandler PriceChanged;

        public decimal Price {
            get {
                return price;
            }
            set {
                if (price == value) return;
                decimal oldPrice = price;
                price = value;
                if(PriceChanged != null)
                {
                    PriceChanged(oldPrice, price);
                }
            }
        }

    }
}

 

以上是关于协变和逆变随笔的主要内容,如果未能解决你的问题,请参考以下文章

协变和逆变之疑问

Java泛型中的协变和逆变

如何检查函数中元素的协变和逆变位置?

Typescript中的协变和逆变

Typescript中的协变和逆变

Typescript中的协变和逆变