Addition of int and uint

前端 未结 6 1080
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-06 09:30

I\'m surprised by C# compiler behavior in the following example:

int i = 1024;
uint x = 2048;
x = x+i;     // A error CS0266: Cannot implicitly convert type          


        
6条回答
  •  误落风尘
    2020-12-06 10:13

    I think the behavior of the compiler is pretty logical and expected.

    In the following code:

    int i;
    int j;
    var k = i + j;
    

    There is an exact overload for this operation, so k is int. Same logic applies when adding two uint, two byte or what have you. The compiler's job is easy here, its happy because the overload resolution finds an exact match. There is a pretty good chance that the person writing this code expects k to be an int and is aware that the operation can overflow in certain circumstances.

    Now consider the case you are asking about:

    uint i;
    int j;
    var k = i + j;
    

    What does the compiler see? Well it sees an operation that has no matching overload; there is no operator + overload that takes an int and a uint as its two operands. So the overload resolution algorithm goes ahead and tries to find an operator overload that can be valid. This means it has to find an overload where the types involved can "hold" the original operands; that is, both i and j have to be implicitly convertible to said type(s).

    The compiler can't implicitly convert uint to int because such conversion doesn't exsit. It cant implicitly convert int to uint either because that conversion also doesn't exist (both can cause a change in magnitude). So the only choice it really has is to choose the first broader type that can "hold" both operand types, which in this case is long. Once both operands are implicitly converted to long k being long is obvious.

    The motivation of this behavior is, IMO, to choose the safest available option and not second guess the dubious coder's intent. The compiler can not make an educated guess as to what the person writing this code is expecting k to be. An int? Well, why not an uint? Both options seem equally bad. The compiler chooses the only logical path; the safe one: long. If the coder wants k to be either int or unit he only has to explicitly cast one of the operands.

    And last, but not least, the C# compiler's overload resolution algorithm does not consider the return type when deciding the best overload. So the fact that you are storing the operation result in a uint is completely irrelevant to the compiler and has no effect whatsoever in the overload resolution process.

    This is all speculation on my part, and I may be completely wrong. But it does seem logical reasoning.

提交回复
热议问题