6

This seems to be a very stupid question about casting, but...

I have the following setup:

There are a number of classes derivces from a main class. At some point in time and space I get an item, and want to handle it as object of subclass.

Asume:

class subClassA : mainclass 
class subClassB : mainclass 

Now I have some if to ask which class it is:

if(someObject is subClassA)
{
    subClassA aA = someObject as subClassA ;
}

While for most subClasses the correct object is returned, I get for one subClass a null-Object.

If I do the following:

if(someObject is subClassA)
{
    subClassA aA = someObject as subClassA ; // <- aA = null; someObject is shown in debugger as object of subClassA

    object test = someObject as subClassA; // <- object is not null
    // or 
    subClassA aB = (subClassA)someObject; // <- object is not null, shows the correct object
}

I have results in test and aB.

What I do not understand:

Why does as fail and the prefix cast succeed?


Now I'm completly lost.

if(someObject is subClassA)
{
    subClassA aA = someObject as subClassA ; // <- aA = null; someObject is shown in debugger as object of subClassA

    subClassA aB = someObject as subClassA ; // <- aB != null.
}

if(someObject is subClassA)
{
    subClassA aB = someObject as subClassA ; // <- aB != null.
}

The name aA is localy defined. Only one thread accesses the method. If I just rename aA it works.

Offler
  • 1,223
  • 1
  • 12
  • 34
  • 2
    Are you certain `someObject` itself is not `null`? – D Stanley Jan 31 '13 at 16:34
  • 1
    The only thing I could think of is that this has to do with a confused type? Are you possibly casting from a type of the same name, but different assembly version? – Justin Pihony Jan 31 '13 at 16:36
  • -stanley I'm sure that someobject is not null - it shows entries and is cast correctly at later lines @pihony copied and pasted the type from the is to both other appearances. therefore all 3 ones should be the same. (that was the one i checked first). The funny thing is that i have used "as" as i have read that "as" should be up to 5 times faster. – Offler Jan 31 '13 at 16:40
  • I think the code can't work the way you describe. Could you include short but complete sample code that shows your problem (including definitions of all classes etc.)? – svick Jan 31 '13 at 17:39
  • 2
    svick is correct; it should *never* be possible to have `if(x is Y) { Y y = x as Y; }` produce null for `y`. (Provided of course that x is not modified!) Please provide a small *complete* program that demonstrates what you're observing here. – Eric Lippert Feb 01 '13 at 01:09
  • @eric lippert: this happens in a 300k liner. The object comes from a OpenAccess query (getting a database object by an objectid, . the code really is in form if(null!=x){if(x is Y){Y y = x as Y;dosomestuffwithy();}else if(x is B){B b = x as B; dosomestuffwithb();}} if i go through the method step by step with a debugger i can see: 1a. x is not null. 1b. If x is Y it works as expected 2a. x is not null 2b. x is B is true 2c. B b = x as B; => b = null. (in debugger, x is still shown as B, and is shown to have values (like a database row ID). – Offler Feb 01 '13 at 07:09
  • Now the funny thing is: the object test above is shown as mainClass object after the cast, not as subClass'n' object – Offler Feb 01 '13 at 07:11
  • @Offler I agree with the others, something crucial is missing from your example: what are you describing it's not possible. If you cannot provide a complete example, can you at least do an ILDasm of the crucial lines there, and post it here? – Lorenzo Dematté Feb 01 '13 at 08:19
  • @dema80 put a version of the working one (renamed variable) and not working one to it, but see no difference? – Offler Feb 01 '13 at 08:58
  • @Offler I think the key is here `stloc.s V_4` VS. `stloc.s aTargetPriceListItemDeliveryZone`. Are you using the same name for more variables? Do you have closures in the nearby code? – Lorenzo Dematté Feb 01 '13 at 09:21
  • @dema80 the same name is used in the following way: ´if(a is A){ A variableName = a as A;} else if {a is B} { B variableName = a as B;}´ As far as i know the variable should only be accessable from within a block as stated in http://msdn.microsoft.com/en-us/library/aa691132(v=vs.71).aspx -> "The scope of a local variable declared in a local-variable-declaration (Section 8.5.1) is the block in which the declaration occurs." As far as I see no clusures in nearby code. – Offler Feb 01 '13 at 09:27
  • You said you're looking at this in the debugger. Are you debugging the *debug* version of the program or the *optimized* version of the program? – Eric Lippert Feb 01 '13 at 15:15
  • @ericlippert the build page is set to debug, is there any difference in debugger afterwards? – Offler Feb 03 '13 at 16:12

3 Answers3

1

The scenario you are describing is confusing to say the least so could you try the following:

subClassA aA = (someObject as subClassA) ?? (subClassA)someObject;

Does that work (eg aA not null)?

You might want to refer to the following post for some details on as:

Casting vs using the 'as' keyword in the CLR

Still investigating some more but I am not sure how to recreate the scenario...

EDIT:

Reading a lot from some very smart people (Skeet and Lippert) trying to find the answer...

See is documenation:

http://msdn.microsoft.com/en-us/library/scekt9xw(v=vs.110).aspx

as / conversion documentation:

http://msdn.microsoft.com/en-us/library/ms173105.aspx

Community
  • 1
  • 1
Kelsey
  • 47,246
  • 16
  • 124
  • 162
  • 1
    Your characterization of the relationship between is, as and cast is not quite right. See onemancat's answer, or my article here: http://blogs.msdn.com/b/ericlippert/archive/2010/09/16/is-is-as-or-is-as-is.aspx – Eric Lippert Feb 01 '13 at 01:07
  • @EricLippert I thought so... the whole question had me pretty confused assuming the OP's scenario was correct which it seems it can be but not as simply as he has stated. I was trying to prove something that is not possible when I should have instead been trying to disprove the OP's scenario. I have removed some of teh comments to not confuse the subject anymore than it already has :) – Kelsey Feb 01 '13 at 03:47
  • subClassA aA = (someObject as subClassA) ?? (subClassA)someObject; => returns an aA which is not null. – Offler Feb 01 '13 at 07:31
  • Okay. it is not working if i use the name of the original variable. The variable is created in the context, If I change the variable name also the normal "as" works. – Offler Feb 01 '13 at 08:14
0

From MSDN, "as" is equivalent to:

expression is type ? (type)expression : (type)null

So, according to MSDN, in your code:

if(someObject is subClassA)
{
    subClassA aA = someObject as subClassA ;
}

is equivalent to

if(someObject is subClassA)
{
    subClassA aA = someObject is subClassA ? (subClassA)someObject : (subClassA)null ;
}

Since someObject is subClassA appears on both lines, the only thing I could think would be either that 1) someObject is actually null in some case; or, 2) you have a multi-threaded application and your code is not thread-safe (i.e., from time to time the "is" line is true, but by the time the "as" line is reached, the implicit "is" has become false.)

Andy
  • 8,432
  • 6
  • 38
  • 76
J.T. Taylor
  • 4,147
  • 1
  • 23
  • 23
  • 2
    You can't have “`null` but compatible with some type”. There is only one `null`. – svick Jan 31 '13 at 18:45
  • 1) i go through the code step by step. the object someObject is not null before the "as" cast, and someObject is not null after the cast. 2) for sure it is a multi-threaded application. But: a) why shoudl this happen only with one "as" cast and not with the others (and always with the one) b) in paralell task view I do not the any other thread using neither object nor method, the object is only build within one thread and accessed from it. c) the statement of kelsey "X a = (someObject as X) ?? (X)someObject;" shows the correct result. (or the "(subClassA)" statement after the "as" statement. – Offler Feb 01 '13 at 07:46
0

While in most cases the correct object is returned, I get sometimes a null-Object.

There's only one simple explanation for your problem. The someObject reference is being modified by another thread. You'll need to use the lock statement to protect it.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • the someObject is created within the thread which consumes it. Also if i look into the debugger i see no changes at the someobject. I meant with most cases: it is a form if(object is A){} else if(object is B){}else if(... most of the cases work, but only one tree "if(object is B)" does not work. In the case where it does not work i can get the correct object with the statement from kelsey's post (subClassA aA = (someObject as subClassA) ?? (subClassA)someObject;), but not with using "as" – Offler Feb 01 '13 at 07:35