CLR Bug ?!

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Hi all,
I suspect a CLR Bug.
Please look like this code fragment !
My question is: why 0 (zero) is a special value in CLR ?!

Thanks all.

Code:

using System;

namespace CLR_Bug
{
class MainClass
{
[STAThread]
static void Main(string[] args)
{
TestClass mytestclass0=new TestClass(0); //Constructor with
SimpleEnum was called !
TestClass mytestclass1=new TestClass(1); //Constructor with object
was called !
TestClass mytestclassneg1=new TestClass(-1); //Constructor with object
was called !
TestClass mytestclass1000=new TestClass(1000);//Constructor with object
was called !
TestClass mytestclassStr=new TestClass("a"); //Constructor with object
was called !
Console.WriteLine("Why this behaviour ?!");
Console.ReadLine();
//Why 0 is a special value ?
}
}

class TestClass
{
public enum SimpleEnum { Red = 0, Blue = 1, Yellow = 2 }
public TestClass(SimpleEnum se) {
Console.WriteLine("Constructor with SimpleEnum was called !");
}
public TestClass(object obj) {
Console.WriteLine("Constructor with object was called !");
}
}
}
 
My question is: why 0 (zero) is a special value in CLR ?!

This isn't a CLR issue. It's a C# compiler feature, since method
overload resolution is performed at compile time.

And the reason is that the literal 0 is implicitly convertible to any
enum type.



Mattias
 
Hi Mattias,

thank you for your answer.

I don't think this is compiler feature for 2 reasons:
1) i know that .NET framework resolvs Calls for overloaded methods (with
object parameter) at run-time and not at compile time
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbls7/html/vblrfvbspec9_3_4.asp)
2) i have tried same test with VB.NET with same results. It is a vb.net
compiler feature too ?!

Thanks in advance.

this is VB.NET code i tried:

Imports System

Module Module1
Sub Main()
Dim mytestclass0 As New TestClass(0) 'Constructor with
SimpleEnum was called !
Dim mytestclass1 As New TestClass(1) 'Constructor with object
was called !
Dim mytestclassneg1 As New TestClass(-1) 'Constructor with object
was called !
Dim mytestclass1000 As New TestClass(1000) 'Constructor with object
was called !
Dim mytestclassStr As New TestClass("a") 'Constructor with object
was called !
Console.WriteLine("Why this behaviour ?!")
Console.ReadLine()
'Why 0 is a special value ?
End Sub
End Module

Class TestClass
Public Enum SimpleEnum
Red = 0
Blue = 1
Yellow = 2
End Enum

Public Sub New(ByVal se As SimpleEnum)
Console.WriteLine("Constructor with SimpleEnum was called !")
End Sub
Public Sub New(ByVal obj As Object)
Console.WriteLine("Constructor with object was called !")
End Sub
End Class



you wrote:
"reason is that the literal 0 is implicitly convertible to any enum type".

Ok ... but why this behaviour only for 0 (zero) and not for 1 (one) !?

They are both int !
 
Andrea said:
Hi Mattias,

thank you for your answer.

I don't think this is compiler feature for 2 reasons:
1) i know that .NET framework resolvs Calls for overloaded methods (with
object parameter) at run-time and not at compile time

That's not true in general. Use ildasm to look at the generated code,
and you'll see exactly what method is going to be invoked in your case.

That is talking about the case where strict semantics are not being
used, which isn't even available as an option in C#, so can't possibly
apply to the C# code you posted. It's not normally applicable to well-
written VB.NET code either, as most VB.NET code should have Option
Strict turned on.
2) i have tried same test with VB.NET with same results. It is a vb.net
compiler feature too ?!

Yes. In both languages, there's an implicit conversion from the literal
0 to any enum. (See section 8.8 of the VB.NET spec, and 13.1.3 of the
ECMA C# spec.)
you wrote:
"reason is that the literal 0 is implicitly convertible to any enum type".

Ok ... but why this behaviour only for 0 (zero) and not for 1 (one) !?

They are both int !

There are various times when it's useful to have such an implicit
conversion - not least when checking for bitwise flags:

if ((testValue & MyEnum.SomeFlag) != 0)

is simpler than

if ((testValue & MyEnum.SomeFlag) != (MyEnum)0)

and is still perfectly clear.
 
Hi Jon,

please look this code:

SqlParameter p0=new SqlParameter("@myparam0",0);
//produce new SqlParameter("@myparam",SqlDbType.BigInt) with DBNull as
parameter's Value
//BigInt because SqlDbType.BigInt is the first value in SqlDbType enum
SqlParameter p1=new SqlParameter("@myparam1",1);
//produce new SqlParameter("@myparam",1) with 1 as paramter's Value and Int
as SqlDbType

if VB.NET and C# compilers has this behaviour ...
If there's an implicit conversion from the literal 0 to enum ...
if i try to use p0.Value in this case i have i logical bug ... i receive an
unexpeted NullReferenceExpetion

Thank you.
Andrea.
 
Andrea said:
please look this code:

SqlParameter p0=new SqlParameter("@myparam0",0);
//produce new SqlParameter("@myparam",SqlDbType.BigInt) with DBNull as
parameter's Value
//BigInt because SqlDbType.BigInt is the first value in SqlDbType enum
SqlParameter p1=new SqlParameter("@myparam1",1);
//produce new SqlParameter("@myparam",1) with 1 as paramter's Value and Int
as SqlDbType

if VB.NET and C# compilers has this behaviour ...

Which they do.
If there's an implicit conversion from the literal 0 to enum ...

Which there is.
if i try to use p0.Value in this case i have i logical bug ... i receive an
unexpeted NullReferenceExpetion

Yes, you do. It's an unfortunate but rare consequence of the
overloading rules, which make life better in the majority of cases. Of
course, the same is true if you want to make a sql parameter where the
actual *value* is a SqlDbType. Unlikely, but still problematic due to
the constructor overloading. Fortunately, a simple cast to object will
work in both cases.

This isn't a bug - it's a design decision which you may not agree with,
but everything's behaving as specified, I believe.
 
Back
Top