惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Jina AI
Jina AI
云风的 BLOG
云风的 BLOG
人人都是产品经理
人人都是产品经理
T
The Blog of Author Tim Ferriss
阮一峰的网络日志
阮一峰的网络日志
罗磊的独立博客
J
Java Code Geeks
博客园 - 聂微东
B
Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
WordPress大学
WordPress大学
腾讯CDC
L
LangChain Blog
Apple Machine Learning Research
Apple Machine Learning Research
Microsoft Azure Blog
Microsoft Azure Blog
D
DataBreaches.Net
The GitHub Blog
The GitHub Blog
美团技术团队
博客园 - Franky
Google DeepMind News
Google DeepMind News
V
V2EX
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
月光博客
月光博客
The Cloudflare Blog

博客园 - Felix Liang

精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件 精进 Spring Boot 02 | Spring Boot 的文档结构、POM 文件格式的介绍,以及 Maven 的使用。 精进 Spring Boot 01 | Spring Boot 入门,用 Spring Boot 写第一个 Hello World How do I get started with Node.js 修改xampp的mysql默认密码和端口 Visual Studio 2013 错误系统找不到指定文件,0x80070002 Daily Build H公司数据同步的总结 VB2010新特性之——标识语言版本的新命令行选项/langversion (Visual Basic) 为什么开发人员不能估算时间? [翻译]SQL Server 未公开的两个存储过程sp_MSforeachtable 和 sp_MSforeachdb 获取应用程序的根Url - Felix Liang - 博客园 Lambda 表达式 Lambda Expressions (Visual Basic) 集合初始化器概览(Visual Basic) VB2010 的隐式续行(Implicit Line Continuation) 自动实现属性 Visual Basic 2010 新特性 VS2008 Tips #009 – 您可以在 ASP.NET 的 Web.config 文件中注册用户控件 VS2008 Tips #008 如何创建ASP.NET Web 用户控件并包含在Web 页面中 - Felix Liang
宽松委托转换(Relaxed delegate conversion)
Felix Liang · 2010-05-18 · via 博客园 - Felix Liang

宽松委托转换(Relaxed delegate conversion)在 Visual Basic 2008 中引入,允许您将子过程或函数赋值给委托或处理器(handlers),尽管它们的签名不一致。因而,绑定到委托变得与绑定方法调用(method invocation)一样。

参数和返回类型

用宽松转换取代精确签名匹配,当 Option Strict 选项要设置为 On 时,需要满足以下两条件:

    * 条件1 传参   

     从委托的每个参数到赋值函数或子过程(assigned function or Sub)的相对应参数,必须存在扩大转换(widening conversion)。在下面的例子中,委托 Del1 有一个 Integer 类型的参数,赋值 lambda 表达式(assigned lambda expressions)的参数 m 的类型必须可以从 Integer 扩大转换,如 Long 或 Double。

      ' 定义委托 Del1.
      Delegate Function Del1(ByVal arg As IntegerAs Integer' Option Strict 为 on 或 off, 都是正确的 lambda 表达式赋值

      
' 整型匹配
      Dim d1 As Del1 = Function(m As Integer3' Integer 扩大为 Long
      Dim d2 As Del1 = Function(m As Long3' Integer 扩大为 Double
      Dim d3 As Del1 = Function(m As Double3

   
      只有 

Option Strict 设置为 Off 的时候,才允许缩小转换(Narrowing conversion。    
    
' 仅当 Option Strict 为 off 才正确:

      
Dim d4 As Del1 = Function(m As StringCInt(m)
      
Dim d5 As Del1 = Function(m As Short) m

    *条件2 返回值

      跟参数相反,从赋值函数或子过程(assigned function or Sub)的返回值类型 到 委托的返回值类型 必须存在扩大转换。下面的例子中,因为委托 Del1的返回类型是 Integer,所以每个赋值 lambda 表达式(assigned lambda expression)必须(可以)扩大到 Integer。

      ' 当 Option Strict 为on 时是正确返回值:

      
' 整型匹配.
      Dim d6 As Del1 = Function(m As Integer) m' Short 扩大为 Integer.
      Dim d7 As Del1 = Function(m As Long) CShort(m)' Byte 扩大为 Integer.
      Dim d8 As Del1 = Function(m As DoubleCByte(m)

如果 Option Strict 设置为 Off,传参和返回值没有扩大转换的限制。

' 仅当 Option Strict 设为 Off 时才正确.

' Integer 型参数没有扩展为 Short 
Dim d9 As Del1 = Function(n As Short) n' 返回值 Long 型没有扩展为 Integer 
Dim d10 As Del1 = Function(n As IntegerCLng(n)

忽略参数规格

宽松委托(Relaxed delegate)允许您完全忽略赋值方法(assigned method)的参数规格

' 定义委托 Del2, 带两个参数
Delegate Function Del2(ByVal arg1 As Integer, ByVal arg2 As StringAs Integer' 赋值 lambda 表达式没有参数,尽管 Del2 有两个参数。因为在本例子中赋值函数(assigned function)
'
 是 lambda 表达式,Option Strict 可以是 On 或者 Off。比较 d16 的声明,赋予了标准的方法。
Dim d11 As Del2 = Function() 3' 参数仍然要传值,不过类型在委托中定义
Console.WriteLine(d11(5"five"))' 错误
'
 Console.WriteLine(d11())
'
 Console.WriteLine(d11(5))

注意,您不能只列某些参数,而忽略其它参数。

' 错误
'
Dim d12 As Del2 = Function(p As Integer) p

忽略参数的特性很有用,特别是在事件处理器(event handler)方面,有很多复杂参数时,而某些参数不使用。这样,处理器直接访问事件所注册控件的状态,并且忽略参数。当不存在歧义时,宽松委托允许您忽略参数。下面的例子,标准的 OnClick 方法可以重写做 RelaxedOnClick。

Sub OnClick(ByVal sender As Object, ByVal e As EventArgs) Handles b.Click
    MessageBox.Show(
"Hello World from" + b.Text)
End SubSub RelaxedOnClick() Handles b.Click
    MessageBox.Show(
"Hello World from" + b.Text)
End Sub

AddressOf 例子

前面例子使用 lambda 表达式,使得类型的关系很明显。然而,同样的关系可以用关键字 AddressOf、Handles、AddHandler 作委托赋值(delegate assignment),类型关系就不那么明显了。

下面的例子,函数 f1, f2, f3, 和 f4 可以赋值给 Del1。

' 声明函数委托 Del1.
Delegate Function Del1(ByVal arg As IntegerAs Integer' Definitions of f1, f2, f3, and f4.
Function f1(ByVal m As IntegerAs Integer
End FunctionFunction f2(ByVal m As LongAs Integer
End FunctionFunction f3(ByVal m As IntegerAs Short
End FunctionFunction f4() As Integer
End Function' 给函数委托 Del1 赋值

' 正确的 AddressOf 赋值,Option Strict 可为 on 或 off:

' Integer parameters of delegate and function match.
Dim d13 As Del1 = AddressOf f1' 整型委托参数扩大为 Long.
Dim d14 As Del1 = AddressOf f2' f3 的 Short 返回类型扩大为 Integer.
Dim d15 As Del1 = AddressOf f3

以下例子仅当 

Option Strict 为 Off 是才正确。' 如果 Option Strict 设置 Off,f4 的参数规范可以省略
Dim d16 As Del1 = AddressOf f4' 函数 d16 仍然需要一个参数,在 Del1 定义的
Console.WriteLine(d16(5))' Not valid.
'
Console.WriteLine(d16())
'
Console.WriteLine(d16(5, 3))

丢弃函数返回值

宽松委托转换(Relaxed delegate conversion)允许您将一个函数(Function)赋值给子过程委托(Sub delegate),忽略掉函数的返回值。但是您不能够将子过程(Sub)赋值给函数委托(Function Delegate)。下面的例子,函数 doubler 的地址复制给 Sub 委托 Del3。

' 定义 Sub 委托 Del3.
Delegate Sub Del3(ByVal arg1 As Integer)' 定义函数 doubler, 显示并返回整型参数的值
Function doubler(ByVal p As IntegerAs Integer
    
Dim times2 = 2 * p
    Console.WriteLine(
"Value of p: " & p)
    Console.WriteLine(
"Double p:   " & times2)
    Return times2
End Function' 您可以把函数赋值给 Sub 委托:
Dim d17 As Del3 = AddressOf doubler' 您可以向普通 Sub 过程一样调用 d17
d17(5)' 您不可以将 d17 作为函数调用,它是一个 Sub 过程,没有返回值。
'
 错误
'
Console.WriteLine(d17(5))