WPF开发-委托(delegate)

前言

官方文档:https://docs.microsoft.com/zh-cn/previous-versions/visualstudio/visual-studio-2010/ms173171(v=vs.100)

委托)是一种定义方法签名的类型。 当实例化委托时,您可以将其实例与任何具有兼容签名的方法相关联。 您可以通过委托实例调用方法。

委托用于将方法作为参数传递给其他方法。 事件处理程序就是通过委托调用的方法。 您可以创建一个自定义方法,当发生特定事件时某个类(例如 Windows 控件)就可以调用您的方法。

委托在C#中是一个语言级特性,而在Java语言中没有直接的对应,但是java利用反射即可实现委托!

Func和Action

Func是一种委托,这是在3.5里面新增的,2.0里面我们使用委托是用Delegate,Func位于System.Core命名空间下,使用委托可以提升效率,例如在反射中使用就可以弥补反射所损失的性能。

Action<T>Func<T,TResult>的功能是一样的,只是Action<T>没有返回值,Func<T,TResult>的最后一个参数为返回值。

参见文章WPF桌面端开发17-多线程和异步

委托概述

委托具有以下特点:

  • 委托类似于 C++ 函数指针,但它们是类型安全的。
  • 委托允许将方法作为参数进行传递。
  • 委托可用于定义回调方法。
  • 委托可以链接在一起;例如,可以对一个事件调用多个方法。
  • 方法不必与委托签名完全匹配。 有关更多信息,请参见 在委托中使用变体(C# 和 Visual Basic))。
  • C# 2.0 版引入了匿名方法)的概念,此类方法允许将代码块作为参数传递,以代替单独定义的方法。 C# 3.0 引入了 Lambda 表达式,利用它们可以更简练地编写内联代码块。 匿名方法和 Lambda 表达式(在某些上下文中)都可编译为委托类型。 这些功能统称为匿名函数。 有关 lambda 表达式的更多信息,请参见 匿名函数)

何时使用委托而不使用接口

委托和接口都允许类设计器分离类型声明和实现。 任何)或结构)都能继承和实现给定的接口)。

可以为任何类上的方法创建委托),前提是该方法符合委托的方法签名。

接口引用或委托可由不了解实现该接口或委托方法的类的对象使用。

既然存在这些相似性,那么类设计器何时应使用委托,何时又该使用接口呢?

在以下情况下,请使用委托:

  • 当使用事件设计模式时。
  • 当封装静态方法可取时。
  • 当调用方不需要访问实现该方法的对象中的其他属性、方法或接口时。
  • 需要方便的组合。
  • 当类可能需要该方法的多个实现时。

在以下情况下,请使用接口:

  • 当存在一组可能被调用的相关方法时。
  • 当类只需要方法的单个实现时。
  • 当使用接口的类想要将该接口强制转换为其他接口或类类型时。
  • 当正在实现的方法链接到类的类型或标识时:例如比较方法。

IComparable) 或泛型版本 IComparable) 就是一个使用单一方法接口而不使用委托的很好的示例。 IComparable 声明 CompareTo) 方法,该方法返回一个整数,指定相同类型的两个对象之间的小于、等于或大于关系。 IComparable 可用作排序算法的基础。 虽然将委托比较方法用作排序算法的基础是有效的,但是并不理想。 因为进行比较的能力属于类,而比较算法不会在运行时改变,所以单一方法接口是理想的。

声明、实例化和使用委托

C# 1.0 及更高版本中,可以按以下示例所示声明委托。

1
2
3
4
5
6
7
8
// Declare a delegate.
delegate void Del(string str);

// Declare a method with the same signature as the delegate.
static void Notify(string name)
{
Console.WriteLine("Notification received for: {0}", name);
}

实例化

1
2
// Create an instance of the delegate.
Del del1 = new Del(Notify);

C# 2.0 提供了更简单的方法来编写上面的声明,如以下示例所示。

1
2
// C# 2.0 provides a simpler way to declare an instance of Del.
Del del2 = Notify;

C# 2.0 及更高版本中,还可以使用匿名方法来声明和初始化委托),如以下示例所示。

1
2
3
// Instantiate Del by using an anonymous method.
Del del3 = delegate(string name)
{ Console.WriteLine("Notification received for: {0}", name); };

C# 3.0 及更高版本中,还可以使用 Lambda 表达式来声明和实例化委托,如以下示例所示。

1
2
// Instantiate Del by using a lambda expression.
Del del4 = name => { Console.WriteLine("Notification received for: {0}", name); };

C# 3.5里面新增FuncAction

1
2
3
4
5
6
7
8
9
public static void threadRun2(Dispatcher dispatcher, Func<string> tFunc, Action<string> mainAction)
{
new Thread(o =>
{
string result = tFunc();
_ = dispatcher.Invoke(mainAction, result);
}
).Start();
}