C#学习,委托,事件,泛型,匿名方法

这篇具有很好参考价值的文章主要介绍了C#学习,委托,事件,泛型,匿名方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

委托

声明委托

实例化委托

委托的多播

委托的用途

事件

通过事件使用委托

声明事件

泛型

泛型的特性

泛型方法

泛型的委托

匿名方法

编写匿名方法的语法


委托

类似于指针,委托是存有对某个方法的引用的一种引用类型变量,引用可以在运行时被改变。特别用于实现事件和回调方法。

声明委托

委托声明决定了可由委托引用的方法。委托可以指向一个具有相同标签的方法。例如,有一个委托:

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);
            Console.WriteLine("Value of Num: {0}", getNum());
            Console.ReadKey();
        }
    }
}

结果:

Value of Num: 75

委托的用途

下面的实例演示了委托的用法。委托 printString 可用于引用带有一个字符串作为输入的方法,并不返回任何东西。

我们使用这个委托来调用两个方法,第一个把字符串打印到控制台,第二个把字符串打印到文件:

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("e:\\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

message.txt文件:

Hello World

事件

事件是在说一个用户操作,比如按键、点击、鼠标移动等,或者是一些提示信息,比如系统生成的通知,应用程序需要在事件发生时响应事件。使用事件机制实现线程间的通信。

通过事件使用委托

事件在类中声明且生成,并且通过使用同一个类或者其他类中的委托与事件处理程序关联。包含事件的类用于发布事,称为发布器类。其他接受该事件的类被称为订阅器类。事件使用发布订阅模型。发布器是一个包含事件和委托定义的对象。事件和委托之间的联系也定义在这个对象中。发布器类的对象调用这个事件,并且通知其他对象。

订阅器是一个介=接受事件并且提供事件处理程序的对象。在发布器类中的委托调用订阅器类中的方法。

声明事件

类的内部声明事件,首先必须声明该事件的委托类型。例如:

public delegate void BoilerLogHandler(string status);

然后,声明事件本身,使用 event 关键字:

// 基于上面的委托定义事件
public event BoilerLogHandler BoilerEventLog;

上面的代码定义了一个名为 BoilerLogHandler 的委托和一个名为 BoilerEventLog 的事件,该事件在生成的时候会调用委托。

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

并且可以使用事件来讲信息记录到日志中:

using System;
using System.IO;
​
namespace BoilerEventAppl
{
​
    // boiler 类
    class Boiler
    {
        private int temp;
        private int pressure;
        public Boiler(int t, int p)
        {
            temp = t;
            pressure = p;
        }
​
        public int getTemp()
        {
            return temp;
        }
        public int getPressure()
        {
            return pressure;
        }
    }
    // 事件发布器
    class DelegateBoilerEvent
    {
        public delegate void BoilerLogHandler(string status);
​
        // 基于上面的委托定义事件
        public event BoilerLogHandler BoilerEventLog;
​
        public void LogProcess()
        {
            string remarks = "O. K";
            Boiler b = new Boiler(100, 12);
            int t = b.getTemp();
            int p = b.getPressure();
            if (t > 150 || t < 80 || p < 12 || p > 15)
            {
                remarks = "Need Maintenance";
            }
            OnBoilerEventLog("Logging Info:\n");
            OnBoilerEventLog("Temparature " + t + "\nPressure: " + p);
            OnBoilerEventLog("\nMessage: " + remarks);
        }
​
        protected void OnBoilerEventLog(string message)
        {
            if (BoilerEventLog != null)
            {
                BoilerEventLog(message);
            }
        }
    }
    // 该类保留写入日志文件的条款
    class BoilerInfoLogger
    {
        FileStream fs;
        StreamWriter sw;
        public BoilerInfoLogger(string filename)
        {
            fs = new FileStream(filename, FileMode.Append, FileAccess.Write);
            sw = new StreamWriter(fs);
        }
        public void Logger(string info)
        {
            sw.WriteLine(info);
        }
        public void Close()
        {
            sw.Close();
            fs.Close();
        }
    }
    // 事件订阅器
    public class RecordBoilerInfo
    {
        static void Logger(string info)
        {
            Console.WriteLine(info);
        }//end of Logger
​
        static void Main(string[] args)
        {
            BoilerInfoLogger filelog = new BoilerInfoLogger("e:\\boiler.txt");
            DelegateBoilerEvent boilerEvent = new DelegateBoilerEvent();
            boilerEvent.BoilerEventLog += new
            DelegateBoilerEvent.BoilerLogHandler(Logger);
            boilerEvent.BoilerEventLog += new
            DelegateBoilerEvent.BoilerLogHandler(filelog.Logger);
            boilerEvent.LogProcess();
            Console.ReadLine();
            filelog.Close();
        }//end of main
​
    }//end of RecordBoilerInfo
}

结果,在目标文件中显示日志为:

Logging Info:
​
Temparature 100
Pressure: 12
​
Message: O. K

泛型

泛型允许编写一个可以在任何类型下一起工作的类和方法,可以通过数据类型的替代参数编写类或方法的规范。当编译器遇到类的构造函数或方法的函数调用时,它会生成代码来处理指定的数据类型。

using System;
using System.Collections.Generic;
​
namespace GenericApplication
{
    public class MyGenericArray<T>
    {
        private T[] array;
        public MyGenericArray(int size)
        {
            array = new T[size + 1];
        }
        public T getItem(int index)
        {
            return array[index];
        }
        public void setItem(int index, T value)
        {
            array[index] = value;
        }
    }
           
    class Tester
    {
        static void Main(string[] args)
        {
            // 声明一个整型数组
            MyGenericArray<int> intArray = new MyGenericArray<int>(5);
            // 设置值
            for (int c = 0; c < 5; c++)
            {
                intArray.setItem(c, c*5);
            }
            // 获取值
            for (int c = 0; c < 5; c++)
            {
                Console.Write(intArray.getItem(c) + " ");
            }
            Console.WriteLine();
            // 声明一个字符数组
            MyGenericArray<char> charArray = new MyGenericArray<char>(5);
            // 设置值
            for (int c = 0; c < 5; c++)
            {
                charArray.setItem(c, (char)(c+97));
            }
            // 获取值
            for (int c = 0; c < 5; c++)
            {
                Console.Write(charArray.getItem(c) + " ");
            }
            Console.WriteLine();
            Console.ReadKey();
        }
    }
}

结果:

0 5 10 15 20
a b c d e

泛型的特性

使用泛型是一种增强程序功能的技术,具体表现在以下几个方面:

  • 它有助于您最大限度地重用代码、保护类型的安全以及提高性能。

  • 您可以创建泛型集合类。.NET 框架类库在 System.Collections.Generic 命名空间中包含了一些新的泛型集合类。您可以使用这些泛型集合类来替代 System.Collections 中的集合类。

  • 您可以创建自己的泛型接口、泛型类、泛型方法、泛型事件和泛型委托。

  • 您可以对泛型类进行约束以访问特定数据类型的方法。

  • 关于泛型数据类型中使用的类型的信息可在运行时通过使用反射获取。

泛型方法

我们可以通过类型参数声明泛型方法,例如:

using System;
using System.Collections.Generic;
​
namespace GenericMethodAppl
{
    class Program
    {
        static void Swap<T>(ref T lhs, ref T rhs)
        {
            T temp;
            temp = lhs;
            lhs = rhs;
            rhs = temp;
        }
        static void Main(string[] args)
        {
            int a, b;
            char c, d;
            a = 10;
            b = 20;
            c = 'I';
            d = 'V';
​
            // 在交换之前显示值
            Console.WriteLine("Int values before calling swap:");
            Console.WriteLine("a = {0}, b = {1}", a, b);
            Console.WriteLine("Char values before calling swap:");
            Console.WriteLine("c = {0}, d = {1}", c, d);
​
            // 调用 swap
            Swap<int>(ref a, ref b);
            Swap<char>(ref c, ref d);
​
            // 在交换之后显示值
            Console.WriteLine("Int values after calling swap:");
            Console.WriteLine("a = {0}, b = {1}", a, b);
            Console.WriteLine("Char values after calling swap:");
            Console.WriteLine("c = {0}, d = {1}", c, d);
            Console.ReadKey();
        }
    }
}

结果:

Int values before calling swap:
a = 10, b = 20
Char values before calling swap:
c = I, d = V
Int values after calling swap:
a = 20, b = 10
Char values after calling swap:
c = V, d = I

将a,b,c,d进行交换,a,b,c,d的类型并不相同。

泛型的委托

可以通过类型参数来定义泛型委托:

using System;
using System.Collections.Generic;
​
delegate T NumberChanger<T>(T n);
namespace GenericDelegateAppl
{
    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<int> nc1 = new NumberChanger<int>(AddNum);
            NumberChanger<int> nc2 = new NumberChanger<int>(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

匿名方法

委托是用于引用与其具有相同标签的方法。换句话说,可以使用委托对象调用可由委托引用的方法。匿名方法 提供了一种传递代码块作为委托参数的技术。匿名方法是没有名称只有主体的方法。在匿名方法中您不需要指定返回类型,它是从方法主体内的 return 语句推断的。

编写匿名方法的语法

匿名方法是通过使用 delegate 关键字创建委托实例来声明的。例如:

delegate void NumberChanger(int n);
NumberChanger nc = delegate(int x)
{
    Console.WriteLine("Anonymous Method: {0}", x);
};

代码块 Console.WriteLine("Anonymous Method: {0}", x); 是匿名方法的主体。

委托可以通过匿名方法调用,也可以通过命名方法调用,即,通过向委托对象传递方法参数。

其中,匿名方法的主体之后要加一个“;”

例如:

using System;
​
delegate void NumberChanger(int n);
namespace DelegateAppl
{
    class TestDelegate
    {
        static int num = 10;
        public static void AddNum(int p)
        {
            num += p;
            Console.WriteLine("Named Method: {0}", num);
        }
​
        public static void MultNum(int q)
        {
            num *= q;
            Console.WriteLine("Named Method: {0}", num);
        }
​
        static void Main(string[] args)
        {
            // 使用匿名方法创建委托实例
            NumberChanger nc = delegate (int x)
            {
                Console.WriteLine("Anonymous Method: {0}", x);
            };
​
            nc(10);
​
            nc = new NumberChanger(AddNum);
​
            nc(5);
​
            nc = new NumberChanger(MultNum);
​
            nc(2);
            Console.ReadKey();
        }
    }
}

结果:

Anonymous Method: 10
Named Method: 15
Named Method: 30

由于匿名方法没有方法签名,只有方法体,所以无法使用命名方法类似的 方法名(); 去调用,所以只能将由委托变量去调用它,换言之,匿名方法将自己唯一拥有的方法主体交给委托,让委托代理执行。文章来源地址https://www.toymoban.com/news/detail-658479.html

到了这里,关于C#学习,委托,事件,泛型,匿名方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • C#学习笔记8:接口、委托、事件

    C#学习笔记8:接口、委托、事件

    今日继续我的C#学习之路,今日学习接口、委托、事件,文章从实践出发学习这三个设计理念,并提供完整源码 目录 1、接口(多重继承): 代码: 运行结果: 2、委托(方法的代理/函数指针): 创建控制台程序实现委托: 遇到的报错及解决: 修改后的代码: 运行结果: 3、

    2024年04月15日
    浏览(11)
  • C# 一个完整的委托、事件学习示例

    该示例符合委托、事件的定义规则,并且可以帮助大家更好地理解委托和事件的使用! 先定义了一个名为 MyEventArgs 的类,继承自 EventArgs ,它包含一个 Message 属性,用于存储传递的消息。 Publisher 类中添加了一个 protected virtual 的方法 OnMyEvent ,用于触发 MyEvent 事件,并传递

    2024年02月07日
    浏览(12)
  • C#:单例,闭包,委托与事件,线程,Parallel,Params,扩展方法,接口与抽象类

    在对泛型的约束中,最常使用的有where 和 new。 其中where是约束所使用的泛型,该泛型必须是where后面的类,或者继承自该类。 new()说明所使用的泛型,必须具有无参构造函数,这是为了能够正确的初始化对象 1.泛型约束class Singleton where T : class,new() 2.静态对象没创

    2024年01月16日
    浏览(8)
  • C#中内置的泛型委托Func与Action

    从C# 3.0起很少需要自己声明委托。 System.Func 是一个泛型委托,它可以表示带有返回值的方法。它可以接受一个到多个输入参数,并返回一个指定类型的结果。 System.Func 委托的最后一个类型参数表示方法的返回值类型。而 System.Action 系列代表返回void的方法。 Func委托有很多种

    2024年02月05日
    浏览(8)
  • c# 事件与委托

    //在C#中, 事件是一种特殊的委托 ,它允许对象通知其他对象发生了某个特定的事件。 //事件通常用于GUI应用程序中,例如当用户单击按钮时,按钮控件会引发Click事件, //然后其他对象可以订阅该事件并执行相应的操作。 //以下是一个简单的示例,演示如何在C#中使用事件和

    2024年02月06日
    浏览(10)
  • 委托与事件(一)——C#版本

    委托与事件(一)——C#版本

      委托是对 函数的封装 ,可以当作给方法的特征指定一个名称。而事件则是 委托的一种特殊形式 ,当发生有意义的事情时,事件对象处理通知过程。   委托是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有 完全相同的行为 。   用例子来说明为

    2023年04月09日
    浏览(16)
  • C#委托和事件简单复习

    太久没用了,简单的复习一下 快速过一遍语法使用 1.定义一个委托类型 只需要在声明的前面加上delegate,其他的就跟声明一个方法(函数)类似 2.使用刚刚声明的委托 需要定义一个返回值跟参数与我们刚刚定义的委托一致 3.然后声明一个SayHello类型(委托)的变量 把

    2024年02月14日
    浏览(9)
  • C# 中的委托和事件机制

    在C#中,委托和事件是非常重要的概念,用于实现程序中的回调和事件处理。在这里,我们将介绍C#中委托和事件机制的基础知识和用法。 委托是一种类似于C/C++函数指针的概念,它允许将方法作为参数传递到其他方法中,以实现回调函数的功能。委托是一种类型,它可以表示

    2023年04月21日
    浏览(13)
  • C# 事件和委托的区别并说明

    C# 事件和委托的区别并说明

    事件是基于委托的,为委托提供了一个发布/订阅机制。可以说事件是一种特殊的委托,他的调用和委托是一样的。 事件的声明 public event 委托类型 事件名称 通常事件的命名以事件名称+Event来命名。如public event delegate NotifyEvent; 事件和委托的区别如下: 事件只能在方法的外部

    2024年02月07日
    浏览(10)
  • C#学习相关系列之匿名方法和Lambda表达式

            匿名方法 顾名思义就是这类方法的特点是不需要特别去定义函数的名字的。一般我们需要一个函数,但又不想花时间去命名它的时候,就可以使用匿名方法。在 C# 中, 匿名方法通常表现为使用 delegate 运算符和 Lambda 表达式。( Lambda 表达式 的本质也是 匿名方法

    2024年02月07日
    浏览(7)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包