469,315 Members | 2,120 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,315 developers. It's quick & easy.

C# equivalent to TryCast

Will somebody convert this for me...

System.Web.UI.HtmlControls.HtmlHead header;
header = TryCast(this.Page.Header, System.Web.UI.HtmlControls.HtmlHead);

<%= Clinton Gallagher
NET csgallagher AT metromilwaukee.com
URL http://clintongallagher.metromilwaukee.com/
MAP http://wikimapia.org/#y=43038073&x=-...8&z=17&l=0&m=h
Nov 27 '06 #1
21 46282
System.Web.UI.HtmlControls.HtmlHead header;
header = this.Page.Header as System.Web.UI.HtmlControls.HtmlHead;
if (header == null)
// cast failed...
else
// cast succeeded...

Best Regards,
Dustin Campbell
Developer Express Inc.
Nov 27 '06 #2
Thanks...

<%= Clinton

"Dustin Campbell" <du*****@no-spam-pleasedevexpress.comwrote in message
news:c1**************************@news.microsoft.c om...
System.Web.UI.HtmlControls.HtmlHead header;
header = this.Page.Header as System.Web.UI.HtmlControls.HtmlHead;
if (header == null)
// cast failed...
else
// cast succeeded...

Best Regards,
Dustin Campbell
Developer Express Inc.


Nov 27 '06 #3
You can also use the "is" keyword

System.Web.UI.HtmlControls.HtmlHead header;

if (this.PageHeader is System.Web.UI.HtmlControls.HtmlHead)
{
header = (this.PageHeader as
System.Web.UI.HtmlControls.HtmlHead);
}

On Nov 28, 7:58 am, "clintonG"
<csgallag...@REMOVETHISTEXTmetromilwaukee.comwrote :
Thanks...

<%= Clinton

"Dustin Campbell" <dust...@no-spam-pleasedevexpress.comwrote in messagenews:c1**************************@news.micr osoft.com...
System.Web.UI.HtmlControls.HtmlHead header;
header = this.Page.Header as System.Web.UI.HtmlControls.HtmlHead;
if (header == null)
// cast failed...
else
// cast succeeded...
Best Regards,
Dustin Campbell
Developer Express Inc.
Nov 27 '06 #4

This works fine as well, but I think the previous example has preference
because it will only cast the object once.

Wiebe Tijsma

ni***********@iinet.net.au wrote:
You can also use the "is" keyword

System.Web.UI.HtmlControls.HtmlHead header;

if (this.PageHeader is System.Web.UI.HtmlControls.HtmlHead)
{
header = (this.PageHeader as
System.Web.UI.HtmlControls.HtmlHead);
}

On Nov 28, 7:58 am, "clintonG"
<csgallag...@REMOVETHISTEXTmetromilwaukee.comwrote :
>Thanks...

<%= Clinton

"Dustin Campbell" <dust...@no-spam-pleasedevexpress.comwrote in messagenews:c1**************************@news.micr osoft.com...
>>System.Web.UI.HtmlControls.HtmlHead header;
header = this.Page.Header as System.Web.UI.HtmlControls.HtmlHead;
if (header == null)
// cast failed...
else
// cast succeeded...
Best Regards,
Dustin Campbell
Developer Express Inc.
Nov 28 '06 #5
I am just curious on why you want to cast at all?

Gabriel Lozano-Morán

"clintonG" <cs*********@REMOVETHISTEXTmetromilwaukee.comwro te in message
news:e5**************@TK2MSFTNGP02.phx.gbl...
Will somebody convert this for me...

System.Web.UI.HtmlControls.HtmlHead header;
header = TryCast(this.Page.Header, System.Web.UI.HtmlControls.HtmlHead);

<%= Clinton Gallagher
NET csgallagher AT metromilwaukee.com
URL http://clintongallagher.metromilwaukee.com/
MAP http://wikimapia.org/#y=43038073&x=-...8&z=17&l=0&m=h

Nov 28 '06 #6
Can somebody explain why this cast and this form of cast is used?

// An object named header is derived (?) from the class HtmlHead
System.Web.UI.HtmlControls.HtmlHead header;

// Using the is keyword this instance of the PageHeader object is typed
// as an HtmlHead object allowing the instance of this.PageHeader object
// to "borrow" properties of an HtmlHead object
this.PageHeader is System.Web.UI.HtmlControls.HtmlHead

I read the "is a" and the "has a" relationship but I don't understand
the "why a" and this is where I burn out.
<%= Clinton Gallagher
"Wiebe Tijsma" <wi*********@CAPITALStijsma.comwrote in message
news:%2****************@TK2MSFTNGP02.phx.gbl...
>
This works fine as well, but I think the previous example has preference
because it will only cast the object once.

Wiebe Tijsma

ni***********@iinet.net.au wrote:
>You can also use the "is" keyword

System.Web.UI.HtmlControls.HtmlHead header;

if (this.PageHeader is System.Web.UI.HtmlControls.HtmlHead)
{
header = (this.PageHeader as
System.Web.UI.HtmlControls.HtmlHead);
}

On Nov 28, 7:58 am, "clintonG"
<csgallag...@REMOVETHISTEXTmetromilwaukee.comwrot e:
>>Thanks...

<%= Clinton

"Dustin Campbell" <dust...@no-spam-pleasedevexpress.comwrote in
messagenews:c1**************************@news.mi crosoft.com...

System.Web.UI.HtmlControls.HtmlHead header;
header = this.Page.Header as System.Web.UI.HtmlControls.HtmlHead;
if (header == null)
// cast failed...
else
// cast succeeded...
Best Regards,
Dustin Campbell
Developer Express Inc.

Nov 28 '06 #7
In fact - the compiled msil is exactly the same but the example which
doesnt use "is" makes one extra read and write to the stack (tho not
being an expert in reading msil I couldnt tell you why)

try it :-)

On Nov 28, 11:51 am, Wiebe Tijsma <wiebeREM...@CAPITALStijsma.com>
wrote:
This works fine as well, but I think the previous example has preference
because it will only cast the object once.

Wiebe Tijsma

nick.fletc...@iinet.net.au wrote:
You can also use the "is" keyword
System.Web.UI.HtmlControls.HtmlHead header;
if (this.PageHeader is System.Web.UI.HtmlControls.HtmlHead)
{
header = (this.PageHeader as
System.Web.UI.HtmlControls.HtmlHead);
}
On Nov 28, 7:58 am, "clintonG"
<csgallag...@REMOVETHISTEXTmetromilwaukee.comwrote :
Thanks...
<%= Clinton
"Dustin Campbell" <dust...@no-spam-pleasedevexpress.comwrote in messagenews:c1**************************@news.micr osoft.com...
>System.Web.UI.HtmlControls.HtmlHead header;
header = this.Page.Header as System.Web.UI.HtmlControls.HtmlHead;
if (header == null)
// cast failed...
else
// cast succeeded...
Best Regards,
Dustin Campbell
Developer Express Inc.
Nov 28 '06 #8
I found the code in VB while trying to learn what options were available to
me to write into the head of the page when using Themes. I need to control
writing linked style sheets *after* the link element generated by the Theme.

<%= Clinton Gallagher

"Gabriel Lozano-Morán" <ab***@frontbridge.comwrote in message
news:%2****************@TK2MSFTNGP03.phx.gbl...
>I am just curious on why you want to cast at all?

Gabriel Lozano-Morán

"clintonG" <cs*********@REMOVETHISTEXTmetromilwaukee.comwro te in message
news:e5**************@TK2MSFTNGP02.phx.gbl...
>Will somebody convert this for me...

System.Web.UI.HtmlControls.HtmlHead header;
header = TryCast(this.Page.Header, System.Web.UI.HtmlControls.HtmlHead);

<%= Clinton Gallagher
NET csgallagher AT metromilwaukee.com
URL http://clintongallagher.metromilwaukee.com/
MAP http://wikimapia.org/#y=43038073&x=-...8&z=17&l=0&m=h


Nov 28 '06 #9
I picked up the code snippet from Accessing the Html Header in ASP.NET 2.0
[1]. I'm trying to make sense of how to use it when using Themes.

<%= Clinton Gallagher

[1] http://weblogs.asp.net/pscott/archiv...30/424039.aspx

"clintonG" <cs*********@REMOVETHISTEXTmetromilwaukee.comwro te in message
news:%2****************@TK2MSFTNGP02.phx.gbl...
>I found the code in VB while trying to learn what options were available to
me to write into the head of the page when using Themes. I need to control
writing linked style sheets *after* the link element generated by the
Theme.

<%= Clinton Gallagher

"Gabriel Lozano-Morán" <ab***@frontbridge.comwrote in message
news:%2****************@TK2MSFTNGP03.phx.gbl...
>>I am just curious on why you want to cast at all?

Gabriel Lozano-Morán

"clintonG" <cs*********@REMOVETHISTEXTmetromilwaukee.comwro te in
message news:e5**************@TK2MSFTNGP02.phx.gbl...
>>Will somebody convert this for me...

System.Web.UI.HtmlControls.HtmlHead header;
header = TryCast(this.Page.Header, System.Web.UI.HtmlControls.HtmlHead);

<%= Clinton Gallagher
NET csgallagher AT metromilwaukee.com
URL http://clintongallagher.metromilwaukee.com/
MAP http://wikimapia.org/#y=43038073&x=-...8&z=17&l=0&m=h



Nov 28 '06 #10
In fact - the compiled msil is exactly the same but the example which
doesnt use "is" makes one extra read and write to the stack (tho not
being an expert in reading msil I couldnt tell you why)

try it :-)
Actually that's not true at all. See http://www.boyet.com/Articles/Double...tiPattern.html
for details. I compiled the example code at that blog entry and got the following
results:

class Program
{
class Foo
{
public int Length { get { return 0; } }
}

static int DoubleCast(object obj)
{
if (obj is Foo)
return ((Foo)obj).Length;

return -1;
}
static int SingleCast(object obj)
{
Foo foo = obj as Foo;
if (foo != null)
return foo.Length;

return -1;
}

static void Main(string[] args) { }
}

DoubleCast compiles to this IL:

..method private hidebysig static int32 DoubleCast(object obj) cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: isinst CastTest.Program/Foo
L_0006: brfalse.s L_0014
L_0008: ldarg.0
L_0009: castclass CastTest.Program/Foo
L_000e: callvirt instance int32 CastTest.Program/Foo::get_Length()
L_0013: ret
L_0014: ldc.i4.m1
L_0015: ret
}

and SingleCast compiles to this:

..method private hidebysig static int32 SingleCast(object obj) cil managed
{
.maxstack 1
.locals init (
[0] CastTest.Program/Foo foo)
L_0000: ldarg.0
L_0001: isinst CastTest.Program/Foo
L_0006: stloc.0
L_0007: ldloc.0
L_0008: brfalse.s L_0011
L_000a: ldloc.0
L_000b: callvirt instance int32 CastTest.Program/Foo::get_Length()
L_0010: ret
L_0011: ldc.i4.m1
L_0012: ret
}

The differeince is the additional "castclass" in DoubleCast at L_0012. This
actually results in two "castclass" operations if you consider the definition
of the "isinst" instruction that appears L_0002:

"isinst <token(0x75). Check to see whether the object reference on the
stack is an instance of the class specified by <token>. <tokenmust be a
valid TypeDef, TypeRef, or TypeSpec token. This instruction takes the object
reference from the stack and pushes the result on the stack. If the check
succeeds, the result is an object reference, **as if castclass had been invoked**;
otherwise, the result is a null reference, as if ldnull had been invoked."
- Expert .NET 2.0 IL Assembler by Serge Lidin, pg. 287 (emphasis mine)

So, in the first example, the IL is not all that optimal because the result
of the "isinst" instruction is compared against null and thrown away -- only
to be recalculated later from the parameter by the "castclass" instruction.
In the second example, the result of the *isinst" instruction is copied to
a local so there isn't any need for "castclass".

Best Regards,
Dustin Campbell
Developer Express Inc.

Nov 28 '06 #11
Hi Dustin,

Interesting stuff.

If you run VS 2005 Code Analysis on the sample code you'll see a warning
about double-casting. It's one of the more annoying warnings produced, IMO.

"Do not cast unnecessarily (CA1800)"
http://msdn2.microsoft.com/en-us/lib...71(vs.80).aspx

Personally, I prefer the code in DoubleCast and I'm not really worried about
any negative impact it may have on performance, normally.

(On a side note, I'd just like to vent a bit: MSDN is terribly slow right
now and it's driving me crazy :)

--
Dave Sexton

"Dustin Campbell" <du*****@no-spam-pleasedevexpress.comwrote in message
news:c1**************************@news.microsoft.c om...
>In fact - the compiled msil is exactly the same but the example which
doesnt use "is" makes one extra read and write to the stack (tho not
being an expert in reading msil I couldnt tell you why)

try it :-)

Actually that's not true at all. See
http://www.boyet.com/Articles/Double...tiPattern.html for details. I
compiled the example code at that blog entry and got the following
results:

class Program
{
class Foo
{
public int Length { get { return 0; } }
}

static int DoubleCast(object obj)
{
if (obj is Foo)
return ((Foo)obj).Length;

return -1;
}
static int SingleCast(object obj)
{
Foo foo = obj as Foo;
if (foo != null)
return foo.Length;

return -1;
}

static void Main(string[] args) { }
}

DoubleCast compiles to this IL:

.method private hidebysig static int32 DoubleCast(object obj) cil managed
{
.maxstack 8
L_0000: ldarg.0 L_0001: isinst CastTest.Program/Foo
L_0006: brfalse.s L_0014
L_0008: ldarg.0 L_0009: castclass CastTest.Program/Foo
L_000e: callvirt instance int32 CastTest.Program/Foo::get_Length()
L_0013: ret L_0014: ldc.i4.m1 L_0015: ret }

and SingleCast compiles to this:

.method private hidebysig static int32 SingleCast(object obj) cil managed
{
.maxstack 1
.locals init (
[0] CastTest.Program/Foo foo)
L_0000: ldarg.0 L_0001: isinst CastTest.Program/Foo
L_0006: stloc.0 L_0007: ldloc.0 L_0008: brfalse.s L_0011
L_000a: ldloc.0 L_000b: callvirt instance int32
CastTest.Program/Foo::get_Length()
L_0010: ret L_0011: ldc.i4.m1 L_0012: ret }

The differeince is the additional "castclass" in DoubleCast at L_0012.
This actually results in two "castclass" operations if you consider the
definition of the "isinst" instruction that appears L_0002:

"isinst <token(0x75). Check to see whether the object reference on the
stack is an instance of the class specified by <token>. <tokenmust be a
valid TypeDef, TypeRef, or TypeSpec token. This instruction takes the
object reference from the stack and pushes the result on the stack. If the
check succeeds, the result is an object reference, **as if castclass had
been invoked**; otherwise, the result is a null reference, as if ldnull
had been invoked." - Expert .NET 2.0 IL Assembler by Serge Lidin, pg. 287
(emphasis mine)

So, in the first example, the IL is not all that optimal because the
result of the "isinst" instruction is compared against null and thrown
away -- only to be recalculated later from the parameter by the
"castclass" instruction. In the second example, the result of the *isinst"
instruction is copied to a local so there isn't any need for "castclass".

Best Regards,
Dustin Campbell
Developer Express Inc.

Nov 28 '06 #12
"Do not cast unnecessarily (CA1800)"
http://msdn2.microsoft.com/en-us/lib...71(vs.80).aspx
Personally, I prefer the code in DoubleCast and I'm not really worried
about any negative impact it may have on performance, normally.
Just as long as you know that the problem is there. I mean, I haven't stopped
using foreach just because it's inefficient in comparisan to say Array.ForEach,
List.ForEach or a hard-coded for or while loop.

Best Regards,
Dustin Campbell
Developer Express Inc.
Nov 28 '06 #13
Hi Dustin,

Agreed.

--
Dave Sexton

"Dustin Campbell" <du*****@no-spam-pleasedevexpress.comwrote in message
news:c1**************************@news.microsoft.c om...
>"Do not cast unnecessarily (CA1800)"
http://msdn2.microsoft.com/en-us/lib...71(vs.80).aspx
Personally, I prefer the code in DoubleCast and I'm not really worried
about any negative impact it may have on performance, normally.

Just as long as you know that the problem is there. I mean, I haven't
stopped using foreach just because it's inefficient in comparisan to say
Array.ForEach, List.ForEach or a hard-coded for or while loop.

Best Regards,
Dustin Campbell
Developer Express Inc.


Nov 28 '06 #14
Hi,
Can somebody explain why this cast and this form of cast is used?
"is" is a binary operator used to check whether a variable "is" of the
specified type or a derived-type. It's commonly used as a predicate in an
"if" statement. "is" does not perform a cast that can be assigned to a
variable.

"as" is a binary operator used to coerce a variable into the specified
reference-type or null if the variable is null or the instance is not of the
specified reference-type or a derived-type. "as" performs a cast that can
be assigned to a variable.

Without the use of "is" and "as" you'd have to use reflection or attempt an
explicit cast, catching InvalidCastException.
// An object named header is derived (?) from the class HtmlHead
System.Web.UI.HtmlControls.HtmlHead header;
In your example a variable named header is typed as HtmlHead. You could
even say that, "header is an instance of HtmlHead", unless of course it's a
null reference, but "derived" is not the appropriate word to use here.
// Using the is keyword this instance of the PageHeader object is typed
// as an HtmlHead object allowing the instance of this.PageHeader object
// to "borrow" properties of an HtmlHead object
this.PageHeader is System.Web.UI.HtmlControls.HtmlHead
The "is" operator returns either true or false. It's used as a comparison,
not for assignment.

In your example, if the PageHeader property returns an instance of an object
that is of the type, "HtmlHead" or a derived type, then the entire "is"
expression will return true, otherwise false:

bool isHtmlHead = this.PageHeader is HtmlHead;

The "as" operator returns the result of the coercion. When the argument
being tested is not null and is of the specified type or a derived type, a
non-null reference will be returned, otherwise null will be returned:

HtmlHead header = this.PageHeader as HtmlHead;

if (header != null)
Trace.WriteLine("PageHeader is an instance of HtmlHead or a derived
type");
else
Trace.WriteLine("PageHeader is null or not an instance of HtmlHead or a
derived type");
I read the "is a" and the "has a" relationship but I don't understand
the "why a" and this is where I burn out.
You got me here - care to clarify this statement?

--
Dave Sexton
Nov 28 '06 #15

"Dave Sexton" <dave@jwa[remove.this]online.comwrote in message
news:Of**************@TK2MSFTNGP04.phx.gbl...
Hi,
>Can somebody explain why this cast and this form of cast is used?

"is" is a binary operator used to check whether a variable "is" of the
specified type or a derived-type. It's commonly used as a predicate in an
"if" statement. "is" does not perform a cast that can be assigned to a
variable.

"as" is a binary operator used to coerce a variable into the specified
reference-type or null if the variable is null or the instance is not of
the specified reference-type or a derived-type. "as" performs a cast that
can be assigned to a variable.

Without the use of "is" and "as" you'd have to use reflection or attempt
an explicit cast, catching InvalidCastException.
>// An object named header is derived (?) from the class HtmlHead
System.Web.UI.HtmlControls.HtmlHead header;

In your example a variable named header is typed as HtmlHead. You could
even say that, "header is an instance of HtmlHead", unless of course it's
a null reference, but "derived" is not the appropriate word to use here.
>// Using the is keyword this instance of the PageHeader object is typed
// as an HtmlHead object allowing the instance of this.PageHeader object
// to "borrow" properties of an HtmlHead object
this.PageHeader is System.Web.UI.HtmlControls.HtmlHead

The "is" operator returns either true or false. It's used as a
comparison, not for assignment.

In your example, if the PageHeader property returns an instance of an
object that is of the type, "HtmlHead" or a derived type, then the entire
"is" expression will return true, otherwise false:

bool isHtmlHead = this.PageHeader is HtmlHead;

The "as" operator returns the result of the coercion. When the argument
being tested is not null and is of the specified type or a derived type, a
non-null reference will be returned, otherwise null will be returned:

HtmlHead header = this.PageHeader as HtmlHead;

if (header != null)
Trace.WriteLine("PageHeader is an instance of HtmlHead or a derived
type");
else
Trace.WriteLine("PageHeader is null or not an instance of HtmlHead or a
derived type");
>I read the "is a" and the "has a" relationship but I don't understand
the "why a" and this is where I burn out.

You got me here - care to clarify this statement?

--
Dave Sexton
Very well said Dave thank you, your sage advice will help me understand
documentation.
Pay no attention to the "why a" it was a facetious reference to "why" this
code snippet should use "is" or "as."

<%= Clinton
Nov 29 '06 #16
Hi Dustin

Youve got me interested now. Ive redone the code which I tested
yesterday which is essentially as follows

double cast
static void Main(string[] args)
{
B myclass = new B();

if (myclass is A)
(myclass as A).GetMyString();
}

single cast
class Program
{
static void Main(string[] args)
{
B myclass = new B();

A a = myclass as A;
if (a != null)
a.GetMyString();
}

Where B is a simple class which derives from A and GetMyString is a
public method on A

These compile to

single cast
..method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 25 (0x19)
.maxstack 2
.locals init ([0] class ConsoleApplication2.B myclass,
[1] class ConsoleApplication2.A a,
[2] bool CS$4$0000)
IL_0000: nop
IL_0001: newobj instance void ConsoleApplication2.B::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: stloc.1
IL_0009: ldloc.1
IL_000a: ldnull
IL_000b: ceq
IL_000d: stloc.2
IL_000e: ldloc.2
IL_000f: brtrue.s IL_0018
IL_0011: ldloc.1
IL_0012: callvirt instance string
ConsoleApplication2.A::GetMyString()
IL_0017: pop
IL_0018: ret
} // end of method Program::Main

double cast

..method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 23 (0x17)
.maxstack 2
.locals init ([0] class ConsoleApplication2.B myclass,
[1] bool CS$4$0000)
IL_0000: nop
IL_0001: newobj instance void ConsoleApplication2.B::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldnull
IL_0009: ceq
IL_000b: stloc.1
IL_000c: ldloc.1
IL_000d: brtrue.s IL_0016
IL_000f: ldloc.0
IL_0010: callvirt instance string
ConsoleApplication2.A::GetMyString()
IL_0015: pop
IL_0016: ret
} // end of method Program::Main

which is obviously contradictory to your findings.

Have I made some fundamental mistake here?

On Nov 29, 1:52 am, Dustin Campbell
<dust...@no-spam-pleasedevexpress.comwrote:
In fact - the compiled msil is exactly the same but the example which
doesnt use "is" makes one extra read and write to the stack (tho not
being an expert in reading msil I couldnt tell you why)
try it :-)Actually that's not true at all. Seehttp://www.boyet.com/Articles/DoubleCastingAntiPattern.html
for details. I compiled the example code at that blog entry and got the following
results:

class Program
{
class Foo
{
public int Length { get { return 0; } }
}

static int DoubleCast(object obj)
{
if (obj is Foo)
return ((Foo)obj).Length;

return -1;
}
static int SingleCast(object obj)
{
Foo foo = obj as Foo;
if (foo != null)
return foo.Length;

return -1;
}

static void Main(string[] args) { }

}DoubleCast compiles to this IL:

.method private hidebysig static int32 DoubleCast(object obj) cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: isinst CastTest.Program/Foo
L_0006: brfalse.s L_0014
L_0008: ldarg.0
L_0009: castclass CastTest.Program/Foo
L_000e: callvirt instance int32 CastTest.Program/Foo::get_Length()
L_0013: ret
L_0014: ldc.i4.m1
L_0015: ret

}and SingleCast compiles to this:

.method private hidebysig static int32 SingleCast(object obj) cil managed
{
.maxstack 1
.locals init (
[0] CastTest.Program/Foo foo)
L_0000: ldarg.0
L_0001: isinst CastTest.Program/Foo
L_0006: stloc.0
L_0007: ldloc.0
L_0008: brfalse.s L_0011
L_000a: ldloc.0
L_000b: callvirt instance int32 CastTest.Program/Foo::get_Length()
L_0010: ret
L_0011: ldc.i4.m1
L_0012: ret

}The differeince is the additional "castclass" in DoubleCast at L_0012. This
actually results in two "castclass" operations if you consider the definition
of the "isinst" instruction that appears L_0002:

"isinst <token(0x75). Check to see whether the object reference on the
stack is an instance of the class specified by <token>. <tokenmust be a
valid TypeDef, TypeRef, or TypeSpec token. This instruction takes the object
reference from the stack and pushes the result on the stack. If the check
succeeds, the result is an object reference, **as if castclass had been invoked**;
otherwise, the result is a null reference, as if ldnull had been invoked."
- Expert .NET 2.0 IL Assembler by Serge Lidin, pg. 287 (emphasis mine)

So, in the first example, the IL is not all that optimal because the result
of the "isinst" instruction is compared against null and thrown away -- only
to be recalculated later from the parameter by the "castclass" instruction.
In the second example, the result of the *isinst" instruction is copied to
a local so there isn't any need for "castclass".

Best Regards,
Dustin Campbell
Developer Express Inc.
Nov 29 '06 #17
<ni***********@iinet.net.auwrote:
Youve got me interested now. Ive redone the code which I tested
yesterday which is essentially as follows

double cast
static void Main(string[] args)
{
B myclass = new B();

if (myclass is A)
(myclass as A).GetMyString();
}

single cast
class Program
{
static void Main(string[] args)
{
B myclass = new B();

A a = myclass as A;
if (a != null)
a.GetMyString();
}

Where B is a simple class which derives from A and GetMyString is a
public method on A
<snip>

In your code, the compiler can work out that an instance of B is
*always* an instance of A, so it doesn't bother with the class.

A better test is:

using System;

class Test
{
static void Main(string[] args)
{
// Dummy method
}

static void DoubleCast (object o)
{
if (o is string)
{
Console.WriteLine ((String) o);
}
}

static void SingleCast (object o)
{
string s = o as string;
if (s != null)
{
Console.WriteLine (s);
}
}
}

Now, I believe that in 1.1 that would use isinst for both methods. In
2.0, it uses the castclass op code for the second cast in DoubleCast.
Couldn't say why - I don't know if castclass is new for 2.0...

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Nov 29 '06 #18
Now, I believe that in 1.1 that would use isinst for both methods. In
2.0, it uses the castclass op code for the second cast in DoubleCast.
That's correct.
Couldn't say why - I don't know if castclass is new for 2.0...
castclass was in 1.0. The difference is this: castclass will throw an InvalidCastException.

Best Regards,
Dustin Campbell
Developer Express Inc.
Nov 29 '06 #19
>Now, I believe that in 1.1 that would use isinst for both methods. In
>2.0, it uses the castclass op code for the second cast in DoubleCast.
That's correct.
Actually, after doing a few more tests, I've seen cases where 2.0 also produces
two isinst opcodes. I suppose it's an optimization for specific cases to
use castclass.

Best Regards,
Dustin Campbell
Developer Express Inc.
Nov 29 '06 #20
Based on your instructions, I created this code:

namespace DoubleCastTTest
{
public class A
{
public string GetMyString()
{
return "Text";
}
}
public class B: A
{
}

public class DoubleCastTest
{
static void DoubleCast()
{
B myclass = new B();

if (myclass is A)
(myclass as A).GetMyString();
}
}
public class SingleCastTest
{
static void SingleCast()
{
B myclass = new B();

A a = myclass as A;
if (a != null)
a.GetMyString();
}
}
}
Have I made some fundamental mistake here?
Your test is a bit flawed because the compiler has absolutely certainty that
B can be down-cast to A. The compiler knows that this is implicitly-convertible.
In fact, you don't need the "is" or "as" operators at all in your code. You
could write this:

B myclass = new B();
A a = myclass;
a.GetMyString();

Or this:

A a = new B();
a.GetMyString();

In addition, you should build in Release mode to see the real production
IL with optimizations. It clears out a lot of noise.

When compiled, I get this IL:

..method private hidebysig static void DoubleCast() cil managed
{
.maxstack 1
.locals init (
[0] DoubleCastTTest.B myclass)
L_0000: newobj instance void DoubleCastTTest.B::.ctor()
L_0005: stloc.0
L_0006: ldloc.0
L_0007: brfalse.s L_0010
L_0009: ldloc.0
L_000a: callvirt instance string DoubleCastTTest.A::GetMyString()
L_000f: pop
L_0010: ret
}

..method private hidebysig static void SingleCast() cil managed
{
.maxstack 1
.locals init (
[0] DoubleCastTTest.B myclass,
[1] DoubleCastTTest.A a)
L_0000: newobj instance void DoubleCastTTest.B::.ctor()
L_0005: stloc.0
L_0006: ldloc.0
L_0007: stloc.1
L_0008: ldloc.1
L_0009: brfalse.s L_0012
L_000b: ldloc.1
L_000c: callvirt instance string DoubleCastTTest.A::GetMyString()
L_0011: pop
L_0012: ret
}

Now, in SingleCast, you had to declare a new local variable to store the
reference returned by "myclass as A". That is why there is more code. In
DoubleCast, the compiler knows that B is implicitly-convertiable to A so
it reuses the same local variable. In fact, because of these implicit-conversions,
the C# compiler could be further optimized to make SingleCast look exactly
like DoubleCast.

OK, so, you've tested the best case scenario -- the one in which there is
absolutely no uncertainty. So, let's throw a little uncertainty into the mix:

namespace DoubleCastTTest
{
public class A
{
public string GetMyString()
{
return "Text";
}
}
public class B: A
{
}

public class DoubleCastTest
{
static void DoubleCast(A a)
{
if (a is B)
(a as B).GetMyString();
}
}
public class SingleCastTest
{
static void SingleCast(A a)
{
B b = a as B;
if (b != null)
b.GetMyString();
}
}
}

In this case, the compiler knows nothing about the instance of A that is
being passed to it so it can't do any optimizations when up-casting to B.
And, here's the IL:

..method private hidebysig static void DoubleCast(DoubleCastTTest.A a) cil
managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: isinst DoubleCastTTest.B
L_0006: brfalse.s L_0014
L_0008: ldarg.0
L_0009: isinst DoubleCastTTest.B
L_000e: callvirt instance string DoubleCastTTest.A::GetMyString()
L_0013: pop
L_0014: ret
}

..method private hidebysig static void SingleCast(DoubleCastTTest.A a) cil
managed
{
.maxstack 1
.locals init (
[0] DoubleCastTTest.B b)
L_0000: ldarg.0
L_0001: isinst DoubleCastTTest.B
L_0006: stloc.0
L_0007: ldloc.0
L_0008: brfalse.s L_0011
L_000a: ldloc.0
L_000b: callvirt instance string DoubleCastTTest.A::GetMyString()
L_0010: pop
L_0011: ret
}

Now the double-cast shows its true colors.

Best Regards,
Dustin Campbell
Developer Express Inc.

Nov 29 '06 #21
Hi Dustin,

Thanks very much for taking the time to go through that. Most helpful

Cheers

Nick

On Nov 30, 1:26 am, Dustin Campbell
<dust...@no-spam-pleasedevexpress.comwrote:
Based on your instructions, I created this code:

namespace DoubleCastTTest
{
public class A
{
public string GetMyString()
{
return "Text";
}
}
public class B: A
{
}

public class DoubleCastTest
{
static void DoubleCast()
{
B myclass = new B();

if (myclass is A)
(myclass as A).GetMyString();
}
}
public class SingleCastTest
{
static void SingleCast()
{
B myclass = new B();

A a = myclass as A;
if (a != null)
a.GetMyString();
}
}

}
Have I made some fundamental mistake here?Your test is a bit flawed because the compiler has absolutely certainty that
B can be down-cast to A. The compiler knows that this is implicitly-convertible.
In fact, you don't need the "is" or "as" operators at all in your code. You
could write this:

B myclass = new B();
A a = myclass;
a.GetMyString();

Or this:

A a = new B();
a.GetMyString();

In addition, you should build in Release mode to see the real production
IL with optimizations. It clears out a lot of noise.

When compiled, I get this IL:

.method private hidebysig static void DoubleCast() cil managed
{
.maxstack 1
.locals init (
[0] DoubleCastTTest.B myclass)
L_0000: newobj instance void DoubleCastTTest.B::.ctor()
L_0005: stloc.0
L_0006: ldloc.0
L_0007: brfalse.s L_0010
L_0009: ldloc.0
L_000a: callvirt instance string DoubleCastTTest.A::GetMyString()
L_000f: pop
L_0010: ret

}.method private hidebysig static void SingleCast() cil managed
{
.maxstack 1
.locals init (
[0] DoubleCastTTest.B myclass,
[1] DoubleCastTTest.A a)
L_0000: newobj instance void DoubleCastTTest.B::.ctor()
L_0005: stloc.0
L_0006: ldloc.0
L_0007: stloc.1
L_0008: ldloc.1
L_0009: brfalse.s L_0012
L_000b: ldloc.1
L_000c: callvirt instance string DoubleCastTTest.A::GetMyString()
L_0011: pop
L_0012: ret

}Now, in SingleCast, you had to declare a new local variable to store the
reference returned by "myclass as A". That is why there is more code. In
DoubleCast, the compiler knows that B is implicitly-convertiable to A so
it reuses the same local variable. In fact, because of these implicit-conversions,
the C# compiler could be further optimized to make SingleCast look exactly
like DoubleCast.

OK, so, you've tested the best case scenario -- the one in which there is
absolutely no uncertainty. So, let's throw a little uncertainty into the mix:

namespace DoubleCastTTest
{
public class A
{
public string GetMyString()
{
return "Text";
}
}
public class B: A
{
}

public class DoubleCastTest
{
static void DoubleCast(A a)
{
if (a is B)
(a as B).GetMyString();
}
}
public class SingleCastTest
{
static void SingleCast(A a)
{
B b = a as B;
if (b != null)
b.GetMyString();
}
}

}In this case, the compiler knows nothing about the instance of A that is
being passed to it so it can't do any optimizations when up-casting to B.
And, here's the IL:

.method private hidebysig static void DoubleCast(DoubleCastTTest.A a) cil
managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: isinst DoubleCastTTest.B
L_0006: brfalse.s L_0014
L_0008: ldarg.0
L_0009: isinst DoubleCastTTest.B
L_000e: callvirt instance string DoubleCastTTest.A::GetMyString()
L_0013: pop
L_0014: ret

}.method private hidebysig static void SingleCast(DoubleCastTTest.A a) cil
managed
{
.maxstack 1
.locals init (
[0] DoubleCastTTest.B b)
L_0000: ldarg.0
L_0001: isinst DoubleCastTTest.B
L_0006: stloc.0
L_0007: ldloc.0
L_0008: brfalse.s L_0011
L_000a: ldloc.0
L_000b: callvirt instance string DoubleCastTTest.A::GetMyString()
L_0010: pop
L_0011: ret

}Now the double-cast shows its true colors.

Best Regards,
Dustin Campbell
Developer Express Inc.
Nov 29 '06 #22

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

14 posts views Thread by John | last post: by
2 posts views Thread by Michael Foord | last post: by
7 posts views Thread by Tim Conner | last post: by
10 posts views Thread by karch | last post: by
9 posts views Thread by Alan Silver | last post: by
14 posts views Thread by grid | last post: by
4 posts views Thread by =?Utf-8?B?TGVvIExleXM=?= | last post: by
1 post views Thread by CARIGAR | last post: by
reply views Thread by zhoujie | last post: by
reply views Thread by harlem98 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.