反射、属性、索引器、委托、事件

32.反射
    反射指程序可以访问、检测和修改它本身状态或行为的一种能力。

    程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。

    您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。

    优缺点
    优点:
    
    1、反射提高了程序的灵活性和扩展性。
    2、降低耦合性,提高自适应能力。
    3、它允许程序创建和控制任何类的对象,无需提前硬编码目标类。
    缺点:
    
    1、性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。
    2、使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术,因而会带来维护的问题,反射代码比相应的直接代码更复杂。
    
    用途:
    它允许在运行时查看特性(attribute)信息。
    它允许审查集合中的各种类型,以及实例化这些类型。
    它允许延迟绑定的方法和属性(property)。
    它允许在运行时创建新类型,然后使用这些类型执行一些任务。
    
    查看元数据:
    上一章节提到通过反射可以获取特性信息,
    System.Reflection 类的 MemberInfo 对象需要被初始化,用于发现与类相关的特性(attribute)。为了做到这点,您可以定义目标类的一个对象,如下:
    System.Reflection.MemberInfo info = typeof(MyClass);
    实例:
        using System;

        //自定义特性
        [AttributeUsage(AttributeTargets.All)]
        public class HelpAttribute : System.Attribute
        {
        private string topic;
        public readonly string Url;
        
        public string Topic  // Topic 是一个命名(named)参数
        {
            get
            {
                return topic;
            }
            set
            {
        
                topic = value;
            }
        }
        
        public HelpAttribute(string url)  // url 是一个定位(positional)参数
        {
            this.Url = url;
        }

        }
        //自定义特性修饰MyClass
        [HelpAttribute("Information on the class MyClass")]
        class MyClass
        {
        }
        
        namespace AttributeAppl
        {
        class Program
        {
            static void Main(string[] args)
            {
                //通过typeof(类名)获取MemberInfo对象
                System.Reflection.MemberInfo info = typeof(MyClass);
                //通过 MemberInfo的GetCustomAttributes方法,获取修饰类的所有特性名称
                object[] attributes = info.GetCustomAttributes(true);
                for (int i = 0; i < attributes.Length; i++)
                {
                    System.Console.WriteLine(attributes[i]);
                }
                //输出结果:HelpAttribute
                Console.ReadKey();
            }
        }
        }
    实例2:通过反射获取修饰类的自定义特性信息
        using System;
        using System.Reflection;
        namespace BugFixApplication
        {
        // 一个自定义特性 BugFix 被赋给类及其成员
        [AttributeUsage(AttributeTargets.Class |
        AttributeTargets.Constructor |
        AttributeTargets.Field |
        AttributeTargets.Method |
        AttributeTargets.Property,
        AllowMultiple = true)]
        
        public class DeBugInfo : System.Attribute
        {
            private int bugNo;
            private string developer;
            private string lastReview;
            public string message;
        
            public DeBugInfo(int bg, string dev, string d)
            {
                this.bugNo = bg;
                this.developer = dev;
                this.lastReview = d;
            }
        
            public int BugNo
            {
                get
                {
                    return bugNo;
                }
            }
            public string Developer
            {
                get
                {
                    return developer;
                }
            }
            public string LastReview
            {
                get
                {
                    return lastReview;
                }
            }
            public string Message
            {
                get
                {
                    return message;
                }
                set
                {
                    message = value;
                }
            }
        }
        [DeBugInfo(45, "Zara Ali", "12/8/2012",
                Message = "Return type mismatch")]
        [DeBugInfo(49, "Nuha Ali", "10/10/2012",
                Message = "Unused variable")]
        class Rectangle
        {
            // 成员变量
            protected double length;
            protected double width;
            public Rectangle(double l, double w)
            {
                length = l;
                width = w;
            }
            [DeBugInfo(55, "Zara Ali", "19/10/2012",
                Message = "Return type mismatch")]
            public double GetArea()
            {
                return length * width;
            }
            [DeBugInfo(56, "Zara Ali", "19/10/2012")]
            public void Display()
            {
                Console.WriteLine("Length: {0}", length);
                Console.WriteLine("Width: {0}", width);
                Console.WriteLine("Area: {0}", GetArea());
            }
        }//end class Rectangle  
        
        class ExecuteRectangle
        {
            static void Main(string[] args)
            {
                Rectangle r = new Rectangle(4.5, 7.5);
                r.Display();
                Type type = typeof(Rectangle);
                // 遍历 Rectangle 类的特性 下述方法中的false表示仅搜索当前成员本身,不包括任何继承的属性
                foreach (Object attributes in type.GetCustomAttributes(false))
                {
                    DeBugInfo dbi = (DeBugInfo)attributes;
                    if (null != dbi)
                    {
                    Console.WriteLine("Bug no: {0}", dbi.BugNo);
                    Console.WriteLine("Developer: {0}", dbi.Developer);
                    Console.WriteLine("Last Reviewed: {0}",
                                                dbi.LastReview);
                    Console.WriteLine("Remarks: {0}", dbi.Message);
                    }
                }
                
                // 遍历方法特性
                foreach (MethodInfo m in type.GetMethods())
                {
                    //下述方法中的true表示会搜索当前成员以及所有父类中的相同属性
                    foreach (Attribute a in m.GetCustomAttributes(true))
                    {
                    DeBugInfo dbi = (DeBugInfo)a;//DeBugInfo dbi = a as DeBugInfo;
                    if (null != dbi)
                    {
                        Console.WriteLine("Bug no: {0}, for Method: {1}",
                                                        dbi.BugNo, m.Name);
                        Console.WriteLine("Developer: {0}", dbi.Developer);
                        Console.WriteLine("Last Reviewed: {0}",
                                                        dbi.LastReview);
                        Console.WriteLine("Remarks: {0}", dbi.Message);
                    }
                    }
                }
                Console.ReadLine();
                //输出结果
                Length: 4.5
                Width: 7.5
                Area: 33.75
                Bug No: 49
                Developer: Nuha Ali
                Last Reviewed: 10/10/2012
                Remarks: Unused variable
                Bug No: 45
                Developer: Zara Ali
                Last Reviewed: 12/8/2012
                Remarks: Return type mismatch
                Bug No: 55, for Method: GetArea
                Developer: Zara Ali
                Last Reviewed: 19/10/2012
                Remarks: Return type mismatch
                Bug No: 56, for Method: Display
                Developer: Zara Ali
                Last Reviewed: 19/10/2012
                Remarks: 
            }
        }
        }

33.属性(Property)
    C# 中的属性(Property)是类和结构体中用于封装数据的成员。它们提供了一种方式来定义类成员的访问和设置规则,通常用于隐藏字段(Fields)的内部实现细节,同时提供控制数据访问的机制。

    属性可以看作是对字段的包装器,通常由 get 和 set 访问器组成。

    属性(Property)不会确定存储位置。相反,它们具有可读写或计算它们值的 访问器(accessors)。
    例如,有名为Person的类,带有age,name,code的私有域,不能在类的范围之外请求这些私有域,但是可以访问这些私有域的属性
    基本语法:Name属性封装了私有字段name,get访问器用于获取值,set访问器用于设置字段值
        public class Person
        {
            private string name;
        
            public string Name
            {
                get { return name; }
                set { name = value; }
            }
        }
    自动实现的属性:只需一个简单的属性,C#允许使用自动实现的属性,便无需显示的定义字段
        public class Person
        {
            public string Name { get; set; }
        }
        上述类中,编译器会自动为Name属性生成一个匿名字段来存储值
    只读属性:如果需要只读属性,可以省略set访问器
        public class Person
        {
            public string Name { get; }
        
            public Person(string name)
            {
                Name = name;
            }
        }
    只写属性:如果只需要一个只写属性,可以省略 get 访问器。    
        public class Person
        {
            private string name;
        
            public string Name
            {
                set { name = value; }
            }
        }
    自定义逻辑:在get和set访问器中包含自定义的逻辑
        public class Person
        {
            private string name;
        
            public string Name
            {
                get { return name; }
                set
                {
                    //如果value为空,则抛出异常
                    if (string.IsNullOrWhiteSpace(value))
                        throw new ArgumentException("Name cannot be empty.");
                    name = value;
                }
            }
        }
    计算属性:属性也可计算,不依赖于字段
        public class Rectangle
        {
            public int Width { get; set; }
            public int Height { get; set; }
        
            //Area属性
            public int Area
            {
                get { return Width * Height; }
            }
        }
    访问器(Accessors)
        属性的访问器包含有助于获取(读取或计算)或设置属性的可执行语句。
        访问器声明可包含一个get访问器、一个set访问器,或者同时包含二者。
        // 声明类型为 string 的 Code 属性
        public string Code
        {
        get
        {
            return code;
        }
        set
        {
            code = value;
        }
        }
        
        // 声明类型为 string 的 Name 属性
        public string Name
        {
        get
        {
            return name;
        }
        set
        {
            name = value;
        }
        }
        
        // 声明类型为 int 的 Age 属性
        public int Age
        { 
        get
        {
            return age;
        }
        set
        {
            age = value;
        }
        }
    实例:声明属性的用法
        using System;
        namespace runoob
        {
        class Student
        {
        
            private string code = "N.A";
            private string name = "not known";
            private int age = 0;
        
            // 声明类型为 string 的 Code 属性
            public string Code
            {
                get
                {
                    return code;
                }
                set
                {
                    code = value;
                }
            }
        
            // 声明类型为 string 的 Name 属性
            public string Name
            {
                get
                {
                    return name;
                }
                set
                {
                    name = value;
                }
            }
        
            // 声明类型为 int 的 Age 属性
            public int Age
            {
                get
                {
                    return age;
                }
                set
                {
                    age = value;
                }
            }
            public override string ToString()
            {
                return "Code = " + Code +", Name = " + Name + ", Age = " + Age;
            }
            }
            class ExampleDemo
            {
            public static void Main()
            {
                // 创建一个新的 Student 对象
                Student s = new Student();
                    
                // 设置 student 的 code、name 和 age
                s.Code = "001";
                s.Name = "Zara";
                s.Age = 9;
                Console.WriteLine("Student Info: {0}", s);
                // 增加年龄
                s.Age += 1;
                Console.WriteLine("Student Info: {0}", s);
                Console.ReadKey();
                //输出结果
                Student Info: Code = 001, Name = Zara, Age = 9
                Student Info: Code = 001, Name = Zara, Age = 10
            }
        }
        }
    抽象属性:抽象类可拥有抽象属性,并在派生类中实现。
        using System;
        namespace Runoob
        {
            public abstract class Person
            {
                //抽象属性也可使用get和set访问器
                public abstract string Name { get; set; }
                public abstract int Age { get; set; }
            }
        
            class Student : Person
            {
                // 声明自动实现的属性
                public string Code { get; set; } = "N.A";
                public override string Name { get; set; } = "N.A";
                public override int Age { get; set; } = 0;
        
                public override string ToString()
                {
                    return $"Code = {Code}, Name = {Name}, Age = {Age}";
                }
            }
        
            class ExampleDemo
            {
                public static void Main()
                {
                    // 创建一个新的 Student 对象
                    Student s = new Student
                    {
                        Code = "001",
                        Name = "Zara",
                        Age = 9
                    };
        
                    Console.WriteLine("Student Info:- {0}", s);
                    
                    // 增加年龄
                    s.Age += 1;
                    Console.WriteLine("Student Info:- {0}", s);
        
                    Console.ReadKey();
                }
            }
        }
    
34.索引器(Indexer)
    索引器(Indexer) 允许一个对象可以像数组一样使用下标的方式来访问。
    当您为类定义一个索引器时,该类的行为就会像一个 虚拟数组(virtual array) 一样。您可以使用数组访问运算符 [ ] 来访问该类的的成员。
    一维索引器语法:
        element-type this[int index] 
        {
        // get 访问器
        get 
        {
            // 返回 index 指定的值
        }
        
        // set 访问器
        set 
        {
            // 设置 index 指定的值 
        }
        }
    索引器用途:
        索引器的行为的声明在某种程度上类似于属性(property)。
        就像属性(property),您可使用 get 和 set 访问器来定义索引器。但是,属性返回或设置一个特定的数据成员,而索引器返回或设置对象实例的一个特定值。
        换句话说,它把实例数据分为更小的部分,并索引每个部分,获取或设置每个部分
        定义一个属性(property)包括提供属性名称。索引器定义的时候不带有名称,但带有 this 关键字,它指向对象实例。
        实例:
        using System;
        namespace IndexerApplication
        {
        class IndexedNames
        {
                //声明namelist属性参数
            private string[] namelist = new string[size];
            static public int size = 10;//namelist元素数量
            public IndexedNames()
            {
                for (int i = 0; i < size; i++)
                namelist[i] = "N. A.";
            }
            //声明索引器
            public string this[int index]
            {
                get
                {
                    string tmp;
        
                    if( index >= 0 && index <= size-1 )
                    {
                    tmp = namelist[index];
                    }
                    else
                    {
                    tmp = "";
                    }
        
                    return ( tmp );
                }
                
                set
                {
                    if( index >= 0 && index <= size-1 )
                    {
                    namelist[index] = value;
                    }
                }
            }
        
            static void Main(string[] args)
            {
                IndexedNames names = new IndexedNames();
                names[0] = "Zara";
                names[1] = "Riz";
                names[2] = "Nuha";
                names[3] = "Asif";
                names[4] = "Davinder";
                names[5] = "Sunil";
                names[6] = "Rubic";
                for ( int i = 0; i < IndexedNames.size; i++ )
                {
                    Console.WriteLine(names[i]);
                }
                Console.ReadKey();
                //输出结果
                Zara
                Riz
                Nuha
                Asif
                Davinder
                Sunil
                Rubic
                N. A. //构造方法中设置的默认值: N. A.
                N. A.
                N. A.
            }
        }
        }
    重载索引器
        索引器(Indexer)可被重载。索引器声明的时候也可带有多个参数,且每个参数可以是不同的类型。没有必要让索引器必须是整型的。C# 允许索引器可以是其他类型,例如,字符串类型。
        using System;
        namespace IndexerApplication
        {
        class IndexedNames
        {
            private string[] namelist = new string[size];
            static public int size = 10;
            public IndexedNames()
            {
                for (int i = 0; i < size; i++)
                {
                namelist[i] = "N. A.";
                }
            }
            //根据索引查找对应的name
            public string this[int index]
            {
                get
                {
                    string tmp;
        
                    if( index >= 0 && index <= size-1 )
                    {
                    tmp = namelist[index];
                    }
                    else
                    {
                    tmp = "";
                    }
        
                    return ( tmp );
                }
                set
                {
                    if( index >= 0 && index <= size-1 )
                    {
                    namelist[index] = value;
                    }
                }
            }
            //根据name查找对应的index
            public int this[string name]
            {
                get
                {
                    int index = 0;
                    while(index < size)
                    {
                    if (namelist[index] == name)
                    {
                        return index;
                    }
                    index++;
                    }
                    return index;
                }
        
            }
        
            static void Main(string[] args)
            {
                IndexedNames names = new IndexedNames();
                names[0] = "Zara";
                names[1] = "Riz";
                names[2] = "Nuha";
                names[3] = "Asif";
                names[4] = "Davinder";
                names[5] = "Sunil";
                names[6] = "Rubic";
                // 使用带有 int 参数的第一个索引器
                for (int i = 0; i < IndexedNames.size; i++)
                {
                    Console.WriteLine(names[i]);
                }
                // 使用带有 string 参数的第二个索引器
                Console.WriteLine(names["Nuha"]);
                Console.ReadKey();
                //输出结果:
                Zara
                Riz
                Nuha
                Asif
                Davinder
                Sunil
                Rubic
                N. A.
                N. A.
                N. A.
                2
            }
        }
        }

35.委托
    C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。

    委托(Delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生自 System.Delegate 类。 
    声明委托
        委托声明决定了可由该委托引用的方法。委托可指向一个与其具有相同标签的方法。
        例如,假设有一个委托:public delegate int MyDelegate(string s);
        上述委托可被用于引用任何一个带有一个单一的string参数的方法,并返回一个int类型变量
        声明委托语法:delegate <return_type> delegate_name (parameter_list);
    实例化委托:一旦声明了委托类型,委托对象就必须使用new关键字来创建,且与一个特定的方法有关。当创建委托时,传递到new 语句的参数就像方法调用一样书写,但是不带有参数。例如;
        public delegate void printString(string s);
        printString ps1 = new printString(WriteToScreen);
        printString ps2 = new printString(WriteToFile);
    实例:创建委托,可用于引用带有一个整数参数的方法,并返回一个整型值。
        using System;

        //声明委托
        delegate int NumberChanger(int n);
        namespace DelegateAppl
        {
        class TestDelegate
        {
            static int num = 10;
            //此处的方法必须是静态方法,否则会报错
            public static int AddNum(int p)
            {
                num += p;
                return num;
            }
            //此处的方法必须是静态方法,否则会报错
            public static int MultNum(int q)
            {
                num *= q;
                return num;
            }
            public static int getNum()
            {
                return num;
            }
        
            static void Main(string[] args)
            {
                // 创建委托实例
                NumberChanger nc1 = new NumberChanger(AddNum);
                NumberChanger nc2 = new NumberChanger(MultNum);
                // 使用委托对象调用方法
                nc1(25);
                Console.WriteLine("Value of Num: {0}", getNum());
                nc2(5);
                Console.WriteLine("Value of Num: {0}", getNum());
                Console.ReadKey();
                
                //输出结果:
                Value of Num: 35
                Value of Num: 175
            }
        }
        }
    委托的多播:
        委托对象可使用 "+" 运算符进行合并。一个合并委托调用它所合并的两个委托。只有相同类型的委托可被合并。"-" 运算符可用于从合并的委托中移除组件委托。

        使用委托的这个有用的特点,您可以创建一个委托被调用时要调用的方法的调用列表。这被称为委托的 多播(multicasting),也叫组播。
        实例:
        using System;
        //声明委托
        delegate int NumberChanger(int n);
        namespace DelegateAppl
        {
        class TestDelegate
        {
            static int num = 10;
            public static int AddNum(int p)
            {
                num += p;
                return num;
            }
        
            public static int MultNum(int q)
            {
                num *= q;
                return num;
            }
            public static int getNum()
            {
                return num;
            }
        
            static void Main(string[] args)
            {
                // 创建委托实例
                NumberChanger nc;
                NumberChanger nc1 = new NumberChanger(AddNum);
                NumberChanger nc2 = new NumberChanger(MultNum);
                nc = nc1;
                nc += nc2; //合并委托
                // 调用多播
                nc(5); //先执行nc1委托对应的AddNum方法,10+5,其次执行委托nc2委托对应的MultNum方法,15*5=75
                Console.WriteLine("Value of Num: {0}", getNum());// 75
                Console.ReadKey();
            }
        }
        }
    委托的用途
        实例:委托pringString可用于引用带有一个字符串输入的方法,并不返回任何东西
        using System;
        using System.IO;
        
        namespace DelegateAppl
        {
        class PrintString
        {
            static FileStream fs;
            static StreamWriter sw;
            // 委托声明
            public delegate void printString(string s);
        
            // 该方法打印到控制台
            public static void WriteToScreen(string str)
            {
                Console.WriteLine("The String is: {0}", str);
            }
            // 该方法打印到文件
            public static void WriteToFile(string s)
            {
                fs = new FileStream("c:\\message.txt", FileMode.Append, FileAccess.Write);
                sw = new StreamWriter(fs);
                sw.WriteLine(s);
                sw.Flush();
                sw.Close();
                fs.Close();
            }
            // 该方法把委托作为参数,并使用它调用方法
            public static void sendString(printString ps)
            {
                ps("Hello World");
            }
            static void Main(string[] args)
            {
                printString ps1 = new printString(WriteToScreen);
                printString ps2 = new printString(WriteToFile);
                sendString(ps1);
                sendString(ps2);
                Console.ReadKey();
                //输出结果:The String is: Hello World
                //同时将Hello World打印到文件中
            }
        }
        }
        
36.事件
    C# 事件(Event)是一种成员,用于将特定的事件通知发送给订阅者。事件通常用于实现观察者模式,它允许一个对象将状态的变化通知其他对象,而不需要知道这些对象的细节。

    事件(Event) 基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些提示信息,如系统生成的通知。应用程序需要在事件发生时响应事件。例如,中断。

    C# 中使用事件机制实现线程间的通信。
    关键点:
        声明委托:定义事件将使用的委托类型。委托是一个函数签名。
        声明事件:使用 event 关键字声明一个事件。
        触发事件:在适当的时候调用事件,通知所有订阅者。
        订阅和取消订阅事件:其他类可以通过 += 和 -= 运算符订阅和取消订阅事件。
    通过事件使用委托    
        事件在类中声明且生成,且通过使用同一个类或其他类中的委托与事件处理程序关联。
        包含事件的类用于发布事件。这被称为 发布器(publisher) 类。
        其他接受该事件的类被称为 订阅器(subscriber) 类。事件使用 发布-订阅(publisher-subscriber) 模型。

        发布器(publisher) 是一个包含事件和委托定义的对象。事件和委托之间的联系也定义在这个对象中。发布器(publisher)类的对象调用这个事件,并通知其他的对象。

        订阅器(subscriber) 是一个接受事件并提供事件处理程序的对象。在发布器(publisher)类中的委托调用订阅器(subscriber)类中的方法(事件处理程序)。    
    声明事件
        在类的内部声明事件,首先必须声明该事件的委托类型。例如:public delegate void BoilerLogHandler(string status);
        然后声明事件本身,使用 event 关键字,例如:public event BoilerLogHandler BoilerEventLog; 事件在生成时会调用委托
        实例:
        using System;

        namespace EventDemo
        {
            // 定义一个委托类型,用于事件处理程序。定义了事件处理程序的签名。通常使用 EventHandler 或 EventHandler<TEventArgs> 来替代自定义的委托。
            public delegate void NotifyEventHandler(object sender, EventArgs e);
        
            // 发布者类
            public class ProcessBusinessLogic
            {
                // 声明事件 是一个使用NotifyEventHandler委托类型点的事件。
                public event NotifyEventHandler ProcessCompleted;
        
                // 触发事件的方法
                protected virtual void OnProcessCompleted(EventArgs e)
                {
                    //是一个受保护的方法,用于触发事件。使用?.Invoke语法来确保只有在订阅者时才调用事件
                    ProcessCompleted?.Invoke(this, e);
                }
        
                // 模拟业务逻辑过程并触发事件
                public void StartProcess()
                {
                    Console.WriteLine("Process Started!");
        
                    // 这里可以加入实际的业务逻辑
        
                    // 业务逻辑完成,触发事件
                    OnProcessCompleted(EventArgs.Empty);
                }
            }
        
            // 订阅者类
            public class EventSubscriber
            {
                public void Subscribe(ProcessBusinessLogic process)
                {
                    //订阅和取消订阅事件。订阅者使用 += 运算符订阅事件,并定义事件处理程序 Process_ProcessCompleted。
                    process.ProcessCompleted += Process_ProcessCompleted;
                }
        
                private void Process_ProcessCompleted(object sender, EventArgs e)
                {
                    Console.WriteLine("Process Completed!");
                }
            }
        
            class Program
            {
                static void Main(string[] args)
                {
                    ProcessBusinessLogic process = new ProcessBusinessLogic();
                    EventSubscriber subscriber = new EventSubscriber();
        
                    // 订阅事件
                    subscriber.Subscribe(process);
        
                    // 启动过程
                    process.StartProcess();
        
                    Console.ReadLine();
                }
            }
        }
    实例2:
        using System;
        namespace SimpleEvent
        {
        using System;
        /***********发布器类***********/
        public class EventTest
        {
            private int value;
            //声明 委托
            public delegate void NumManipulationHandler();
        
            //声明委托事件
            public event NumManipulationHandler ChangeNum;
            protected virtual void OnNumChanged()
            {
            if ( ChangeNum != null )
            {
                ChangeNum(); /* 事件被触发 */
            }else {
                Console.WriteLine( "event not fire" );
                Console.ReadKey(); /* 回车继续 */
            }
            }
        
        
            public EventTest()
            {
                int n = 5;
                SetValue( n );
            }
        
        
            public void SetValue( int n )
            {
            if ( value != n )
            {
                value = n;
                OnNumChanged();
            }
            }
        }
        
        
        /***********订阅器类***********/
        
        public class subscribEvent
        {
            public void printf()
            {
            Console.WriteLine( "event fire" );
            Console.ReadKey(); /* 回车继续 */
            }
        }
        
        /***********触发***********/
        public class MainClass
        {
            public static void Main()
            {
            EventTest e = new EventTest(); /* 实例化对象,第一次没有触发事件 */
            subscribEvent v = new subscribEvent(); /* 实例化对象 */
            e.ChangeNum += new EventTest.NumManipulationHandler( v.printf ); /* 注册 */
            e.SetValue( 7 );
            e.SetValue( 11 );
            
            //输出结果
            event not fire
            event fire
            event fire
            }
        }
        }
    实例2:简单的热水锅炉系统故障排除的应用程序,当维修工程师检查时,锅炉的温度和压力会随着维系工程师的备注自动记录到日志文件中
        using System;
        using System.IO;
        
        namespace BoilerEventAppl
        {
            // Boiler 类
            class Boiler
            {
                public int Temp { get; private set; }
                public int Pressure { get; private set; }
        
                public Boiler(int temp, int pressure)
                {
                    Temp = temp;
                    Pressure = pressure;
                }
            }
        
            // 事件发布器
            class DelegateBoilerEvent
            {
                public delegate void BoilerLogHandler(string status);
        
                // 基于上面的委托定义事件
                public event BoilerLogHandler BoilerEventLog;
        
                public void LogProcess()
                {
                    string remarks = "O.K.";
                    Boiler boiler = new Boiler(100, 12);
                    int temp = boiler.Temp;
                    int pressure = boiler.Pressure;
        
                    if (temp > 150 || temp < 80 || pressure < 12 || pressure > 15)
                    {
                        remarks = "Need Maintenance";
                    }
        
                    OnBoilerEventLog($"Logging Info:\nTemperature: {temp}\nPressure: {pressure}\nMessage: {remarks}");
                }
        
                protected void OnBoilerEventLog(string message)
                {
                    BoilerEventLog?.Invoke(message);
                }
            }
        
            // 该类保留写入日志文件的条款
            class BoilerInfoLogger : IDisposable
            {
                private readonly StreamWriter _streamWriter;
        
                public BoilerInfoLogger(string filename)
                {
                    _streamWriter = new StreamWriter(new FileStream(filename, FileMode.Append, FileAccess.Write));
                }
        
                public void Logger(string info)
                {
                    _streamWriter.WriteLine(info);
                }
        
                public void Dispose()
                {
                    _streamWriter?.Close();
                }
            }
        
            // 事件订阅器
            public class RecordBoilerInfo
            {
                static void Logger(string info)
                {
                    Console.WriteLine(info);
                }
        
                static void Main(string[] args)
                {
                    using (BoilerInfoLogger fileLogger = new BoilerInfoLogger("e:\\boiler.txt"))
                    {
                        DelegateBoilerEvent boilerEvent = new DelegateBoilerEvent();
                        boilerEvent.BoilerEventLog += Logger;
                        boilerEvent.BoilerEventLog += fileLogger.Logger;
                        boilerEvent.LogProcess();
                        //写入文件的内容
                        Logging info:

                        Temperature 100
                        Pressure 12
                        
                        Message: O. K

                    }
        
                    Console.ReadLine();
                }
            }
        }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值