奇怪的转换操作符行为

时间:2015-10-01 19:45:10

标签: c#

我有这个结构:

public struct MyValue
{
    public string FirstPart { get; private set; }
    public string SecondPart { get; private set; }

    public static implicit operator MyValue(string fromInput)
    { // first breakpoint here.
        var parts = fromInput.Split(new[] {'@'});
        return new MyValue(parts[0], parts[1]);
    }

    public static implicit operator string(MyValue fromInput)
    { // second breakpoint here.
        return fromInput.ToString();
    }

    public override string ToString()
    {
        return FirstPart + "@" + SecondPart;
    }

    public MyValue(string firstPart, string secondPart) : this()
    {
        this.FirstPart = firstPart;
        this.SecondPart = secondPart;
    }
}

我已根据上述评论设定了断点。

然后我这样做:

var first = new MyValue("first", "second");
if (first == (MyValue) null) throw new InvalidOperationException();

当它进入if (first == (MyValue) null)时,我观察到一些奇怪的行为:第二个断点由于某种原因被击中。为什么尝试将MyValue转换为字符串以进行简单的相等比较?

然后,如果我让代码继续,它会碰到第一个断点,现在我想知道为什么它试图转换一个字符串(值为null尽管事实上我已明确地转换null MyValue MyValueif (first == (MyValue) null)?使用像/* Dropdown Menu Trucks*/ $("#menu-main-menu .show-dropdown").hover(function(){ $("#dropdown").slideDown('fast'); }); $("#dropdown").mouseenter(function(){ $("#dropdown").show(); }); $("#dropdown").mouseleave(function(){ $("#dropdown").slideUp('fast'); }); // ---------------------------- /* Dropdown Menu Engines */ $("#menu-main-menu .show-dropdown2").hover(function(){ $(".dropdown-engines").slideDown('fast'); }); $(".dropdown-engines").mouseenter(function(){ $(".dropdown-engines").show(); }); $(".dropdown-engines").mouseleave(function(){ $(".dropdown-engines").slideUp('fast'); }); if ($('#dropdown').is(':visible')) { $(".dropdown-engines").slideUp(); } else if ($('.dropdown-engines').is(':visible')) { $("#dropdown").slideUp(); } 这样的语句时不应该涉及字符串,那么这里实际发生了什么?

2 个答案:

答案 0 :(得分:12)

忙于评论,问题就变得清晰了。

C#编译器无法编译(MyStruct) null,但在你的情况下它会编译。

这是因为你有一个来自引用类型的隐式运算符(这种情况为stringnull完全有效。

我认为你现在可以遵循为什么它以你看到的方式执行:)

PS:这是一个很好的例子,为什么'有损'一般不鼓励隐式算子。

答案 1 :(得分:7)

要完成@leppies answer,这是调用代码(发布模式):

public void X()
{
    var first = new MyValue("first", "second");
    if (first == (MyValue) null) throw new InvalidOperationException();
}

实际上编译的是:

public void X()
{
    if (new MyValue("first", "second") == null)
    {
        throw new InvalidOperationException();
    }
}

这是呼叫发出的IL:

// Methods
.method public hidebysig 
    instance void X () cil managed 
{
    // Method begins at RVA 0x20dc
    // Code size 45 (0x2d)
    .maxstack 8

    IL_0000: ldstr "first"
    IL_0005: ldstr "second"
    IL_000a: newobj instance void MyValue::.ctor(string, string)
    IL_000f: call string MyValue::op_Implicit(valuetype MyValue)
    IL_0014: ldnull
    IL_0015: call valuetype MyValue MyValue::op_Implicit(string)
    IL_001a: call string MyValue::op_Implicit(valuetype MyValue) <--- This!
    IL_001f: call bool [mscorlib]System.String::op_Equality(string, string)
    IL_0024: brfalse.s IL_002c
    IL_0026: newobj instance void [mscorlib]System.InvalidOperationException::.ctor()
    IL_002b: throw
    IL_002c: ret
} // end of method C::X

正如您所看到的,在创建MyValue的新实例后,操作IL_001a调用隐式转换为string,因为是编译器的唯一可能性使值类型比较null实际编译。