为什么 "as" 运算符在 C# 中不使用隐式转换运算符?

21

我在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吗?是否存在非静态转换操作符?

P.S. 实际上,我最感兴趣的是编译时行为和运行时行为之间的差异,因此我有一个后续问题:为什么 C# 中的隐式类型转换操作符不能在运行时动态使用?


3
顺带一提,我以前从未听说过as运算符被称为“软转换”。 - Jon Skeet
@JonSkeet,这真的让我感到惊讶,也许不是官方术语,但我肯定已经看过很多次了。 - MarioDS
1
@JonSkeet,有没有类似简洁(但更正确)的等效术语? - Richard Ev
@JonSkeet 如果我在更正式或公开的交流中需要它,我会记住这个建议。但我认为最重要的是我的队友们能够理解我使用它的时候。 - MarioDS
2
但在那种情况下,您只是在团队内加强非标准术语的使用。如果您使用标准术语,我认为他们也会理解您,但当讨论外部事物时,您和团队中的任何人都不必改变说话方式。 - Jon Skeet
显示剩余10条评论
4个回答

20
软转换为什么不使用隐式转换器呢? 这基本上是语言规范的规定。从C# 5规范的第7.10.11节可以看出:

If the compile-time type of E is not dynamic, the operation E as T produces the same result as

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

except that E is only evaluated once.

[...]

Note that some conversions, such as user defined conversions, are not possible with the as operator and should instead be performed using cast expressions.


这很清楚,但你知道有什么解决方法吗?如果我真的想要一个行为几乎完全像字符串(或整数,或其他任何东西)的类型,该怎么办? - MarioDS
2
@MDeSchaepmeester:说实话,我会放弃这个目标。当试图使一种类型透明地看起来像另一种类型时,总会遇到问题。我建议回溯并考虑其他设计方案。 - Jon Skeet
说得对,但如果没有这个限制,一切都会很顺利的。无论如何,还是谢谢你,如果你不知道解决方法,我相信其他人也不知道 :) - MarioDS

10

as关键字不考虑用户定义的运算符。您需要使用类型转换运算符。相关来自Eric Lippert的文章

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


使用 dynamic 应该可以使转换起作用,我相信。(不过还需要检查一下。)但这对 as 是没有帮助的。 - Jon Skeet
换句话说,只有在参数实际上是 string 实例的时候,强制转换才会起作用? - MarioDS
没错,已添加支持文章。 - Sriram Sakthivel

9

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

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

因此,您需要进行强制转换。


2
假设需要调用隐式转换运算符。在这种情况下,任何调用

var castObj = rawObj as SomeType;

都需要.NET运行时使用反射来确定“rawObj”对象是否具有转换运算符。显然,这比仅检查对象是否为SomeType或其子类型要计算成本高得多。拥有快速和可预测的运算符比更灵活但慢得多的运算符更好。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接