为啥“as”运算符在 C# 中不使用隐式转换运算符?

Posted

技术标签:

【中文标题】为啥“as”运算符在 C# 中不使用隐式转换运算符?【英文标题】:Why does the "as" operator not use an implicit conversion operator in C#?为什么“as”运算符在 C# 中不使用隐式转换运算符? 【发布时间】:2016-06-01 04:30:53 【问题描述】:

我已经在 C#(虚拟代码)中定义了从/到某种类型的隐式字符串转换:

public class MyType

    public string Value  get; set; 

    public static implicit operator MyType(string fromString)
    
        return new MyType  Value = fromString ;
    

    public static implicit operator string(MyType myType)
    
        return myType.Value;
    

在外部库代码的某处,MyType 的实例作为object 参数传递给方法。该方法的一部分看起来像这样:

private void Foo(object value)

    // ... code omitted
    var bar = value as string // note that value is an instance of MyType at runtime
    if(bar != null) // false, cast fails
    
       // ... code omitted
    

为什么强制转换不使用隐式转换器?我认为这些的全部意义在于使投射和透明使用成为可能?

如果 MyType 有一个 explicit 转换器,这会起作用吗?如果是这样,(如何)我可以两者兼得?

顺便说一句,如果类型在编译时已知,则强制转换肯定有效。这是因为运营商是static吗?有没有类似非静态转换运算符的东西?

附:我实际上对编译时行为和运行时行为之间的差异最感兴趣,所以我有一个后续问题:Why are implicit type conversion operators not dynamically usable at runtime in C#?

【问题讨论】:

顺便说一句,我以前从未听说过 as 运算符被称为“软演员”。 @JonSkeet 真的让我吃惊,也许不是官方术语,但我肯定见过很多次。 搜索“软演员”和 C# 得到 636 个结果,在我看来,这是一个 数字。我以后肯定会避免使用它——它肯定不是 C#规范术语的一部分。 @JonSkeet 是否有类似简洁(但更正确)的等效术语? @MDeSchaepmeester:但在这种情况下,您只是在团队中加强了对非标准术语的使用。如果您使用标准术语,我怀疑他们会理解您 - 但在外部讨论事物时,你们中的任何人都不必改变您的谈话方式。 【参考方案1】:

as 关键字不考虑用户定义的运算符。您需要改用强制转换运算符。相关article from Eric Lippert

在您的情况下,显式和隐式运算符都无法帮助您,因为您尝试从object 转换为string 而不是从MyType 转换为string。要使用户定义的转换运算符起作用,请将实例的时间类型编译为 MyType 类型而不是 object。因为不存在从objectstring 而是从MyTypestring 的转换。

【讨论】:

我相信使用dynamic 会使演员表工作。 (不过必须检查一下。)不过,这对 as 没有帮助。 换句话说,只有当参数实际上是 string 的实例时,演员才会起作用? 没错。添加了支持文章。【参考方案2】:

想象一下,必须调用隐式转换运算符。在这种情况下,任何调用

var castObj = rawObj as SomeType;

将需要 .NET 运行时使用反射来确定“rawObj”对象是否具有转换运算符。显然,这将比仅仅检查对象是 SomeType 类型还是它的子类型更昂贵。拥有一个快速且可预测的运算符比一个更通用但速度慢得多的运算符更好。

【讨论】:

【参考方案3】:

C# 语言规范在 as 的文档中明确提到了这一点:

请注意,某些转化(例如用户定义的转化)不是 可以使用 as 运算符,而是应该使用 转换表达式。

所以你必须投射它。

【讨论】:

【参考方案4】:

为什么软转换不使用隐式转换器?

嗯,基本上就是这样指定语言的。来自 C# 5 规范第 7.10.11 节:

如果 E 的编译时类型不是动态的,则操作 E as T 产生的结果与

E is T ? (T)(E) : (T)null

除了 E 只计算一次。

[...]

请注意,某些转换(例如用户定义的转换)不能使用 as 运算符进行,而应使用强制转换表达式来执行。

【讨论】:

这很清楚,但是您知道任何解决方法吗?如果我真的想要一个行为几乎完全像字符串(或 int 或其他任何东西)的类型怎么办? @MDeSchaepmeester:说实话,我会放弃这个目标。当试图让一种类型看起来像另一种一样透明时,总是会出现问题。我会回溯并查看其他设计。 很公平,但如果不是因为这一限制,一切都会顺利进行。无论如何,谢谢,如果您不知道解决方法,那么我敢肯定没有其他人会这样做:)

以上是关于为啥“as”运算符在 C# 中不使用隐式转换运算符?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Linq Cast<> 助手不能与隐式转换运算符一起使用?

为啥Java在使用“加号”运算符时会执行从双精度到整数的隐式类型转换? [复制]

C# 隐式转换和 == 运算符

面向对象 is和as运算符,类库,委托

C# 隐式运算符 MyType(int value) 自动“支持”从浮点数转换

为啥从 <T> 到 <U> 的隐式转换运算符接受 <T?>?