关于隐式强制转换,我对C#如何处理lambda表达式感到有点困惑.

我的目标类似于下面这个最小的例子:

A<int>.DoSomething(x => x == 42);

public static class A<T>
{
    public static void DoSomething(PredicateAdapter<T> _) { }
}

public class PredicateAdapter<T>
{
    public static implicit operator PredicateAdapter<T>(Predicate<T> _) => new();
}

所以我想为谓词创建一个包装器,它允许我做一些奇特的事情(为简洁起见,在本例中没有列出).然而,上面的代码不能编译,因为"错误CS1660:无法将lambda表达式转换为‘PredicateAdapter’类型,因为它不是委托类型".

相比之下,以下是隐式强制转换的工作原理的示例:

A<int>.DoSomething(x => x == 42);

public static class A<T>
{
    public static void DoSomething(Predicate<T> _) { }
}

编译器能够推断Lambda表达式x => x == 42可以被隐式地强制转换为Predicate<int>,并且将其愉快地传递给A<int>.DoSomething(Predicate<int>).

此外,将lambda显式强制转换为Predicate<int>意味着将应用我的自定义隐式强制转换并工作:

A<int>.DoSomething((Predicate<int>)(x => x == 42));

public static class A<T>
{
    public static void DoSomething(PredicateAdapter<T> _) { }
}

public class PredicateAdapter<T>
{
    public static implicit operator PredicateAdapter<T>(Predicate<T> _) => new();
}

所以我的问题是为什么我需要显式地转换lambda(并且编写可读性更差的代码),而C#显然能够隐式地进行这种转换?并且:有没有可能修改类APredicateAdapter,使我可以使用一个简单的lambda表达式(没有任何显式的转换),仍然使用PredicateAdapter

推荐答案

根据我的理解,这是"因为规范是这样说的".正如第12.19 Anonymous function expressions节所述:

匿名函数本身没有值或类型,但可以转换为兼容的委托或表达式树类型.

因此,当您使用匿名函数(lambda表达式)时,编译器应该决定它应该是什么类型(因为您没有显式指定类型).由于您的参数不是委托类型(如Predicate<T>)或表达式树类型(如Expression<Func<T, TResult>>),编译器会产生错误.

同样是从10.7 Anonymous function conversions岁起:

anonymous_method_expressionlambda_expression被归类为匿名函数(§12.19).该表达式没有类型,但可以隐式转换为兼容的委托类型.还可以将一些lambda表达式隐式转换为兼容的表达式树类型.

同样,C#10中的Lambda improvements也是一个有趣的读物.

Csharp相关问答推荐

碰撞检测与盒碰撞器,其isTrigger on问题

C#DateTime.ToString在ubuntu和centos中返回不同的结果

(乌龙)1&#比c#中的UL&#慢吗?

C#EF Core 8.0表现与预期不符

XUNIT是否使用测试数据的源生成器?

如何使用新的Microsoft.IdentityModel.JsonWebToken创建JwtSecurityToken?

为具有实体框架后端的Reaction项目 Select 正确的Visual Studio模板

如何使用MailKit删除邮箱?

将类移动到新命名空间后更新RavenDB Raven-Clr-Type

.NET8->;并发词典总是比普通词典快...怎么回事?[包含基准结果和代码]

我的命名管道在第一次连接后工作正常,但后来我得到了System.ObjectDisposedException:无法访问关闭的管道

RCL在毛伊岛应用程序和Blazor服务器应用程序.Net 8.0中使用页面

Visual Studio 17.8.0制表符自动完成问题--三缩进

如何设置WinForms按钮焦点,使其看起来像是被Tab键插入其中?

Xamarin Forms应用程序中登录页面的用户名和密码编辑文本之间不需要的空格

Xamarin中出错.表单:应用程序的分部声明不能指定不同的基类

HttpClient,上传文件时实现进度

使用Try-Catch-Finally为API端点处理代码--有什么缺点?

LINQ在GROUP BY和JOIN之后获取子列表

如何查找Span;T&>是否包含相同顺序的其他Span<;T&>