Home All Groups Group Topic Archive Search About
Author
19 Feb 2005 9:55 AM
Andrea

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 !");
        }
    }
}
Author
19 Feb 2005 10:35 AM
Mattias Sjögren
>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

--
Mattias Sjögren [MVP]  mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
Are all your drivers up to date? click for free checkup

Author
19 Feb 2005 1:09 PM
Andrea
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 !



Show quoteHide quote
"Mattias Sjögren" wrote:

>
> >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
>
> --
> Mattias Sjögren [MVP]  mattias @ mvps.org
> http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
> Please reply only to the newsgroup.
>
Author
19 Feb 2005 1:40 PM
Jon Skeet [C# MVP]
Andrea <And***@discussions.microsoft.com> wrote:
> 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.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Author
19 Feb 2005 2:03 PM
Andrea
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.

Show quoteHide quote
"Jon Skeet [C# MVP]" wrote:

> Andrea <And***@discussions.microsoft.com> wrote:
> > 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.
>
> > (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbl
> > s7/html/vblrfvbspec9_3_4.asp)
>
> 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.
>
> --
> Jon Skeet - <sk***@pobox.com>
> http://www.pobox.com/~skeet
> If replying to the group, please do not mail me too
>
Author
19 Feb 2005 7:48 PM
Jon Skeet [C# MVP]
Andrea <And***@discussions.microsoft.com> wrote:
> 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.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

Bookmark and Share