.NET Forum / .NET Framework / New Users / June 2007
Debug this if you can.
|
|
Thread rating:  |
GeezerButler - 02 Jun 2007 14:06 GMT I have a class A derived from interface B. I create object of A (using reflection) and then i try to cast the object A to type B,
object objA = MyReflectionFunction("classA"); B objB = (B) objA; //Exception thrown here
I get Invalid cast exception.
Now the funnier part is that before/after the offending line is executed, if i copy B objB = (B) objA; to the immediate window is VS2005, then it gets executed without a problem.
This has me stumped now for the last few hours.
Can you help in any way. Thanks!
GeezerButler - 02 Jun 2007 16:44 GMT > I have a class A derived from interface B. > I create object of A (using reflection) and then i try to cast the [quoted text clipped - 15 lines] > Can you help in any way. > Thanks! Forget the interface, i cant even get this to work.
object objA = MyReflectionFunction("classA"); if (!objA .GetType().Equals(typeof(A))) { throw new Exception("wrong type"); //throws exception here } Seems like the objA is not of type A, so i printed out all the public properties of the types and all of them are same. I can't see why the types are different. Is there some way to know what exactly is causing the InvalidCastException?
I'm totally foxed now :(
Peter Duniho - 02 Jun 2007 17:16 GMT > I have a class A derived from interface B. > I create object of A (using reflection) and then i try to cast the [quoted text clipped - 7 lines] > [...] > This has me stumped now for the last few hours. It seems to me that you've left out the very most important elements of your question. In particular, you have not included the definition of "MyReflectionFunction", nor of class A and interface B.
The code that fails isn't particular interesting without those.
Pete
GeezerButler - 02 Jun 2007 18:42 GMT On Jun 2, 9:16 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com> wrote:
> > I have a class A derived from interface B. > > I create object of A (using reflection) and then i try to cast the [quoted text clipped - 15 lines] > > Pete Well MyReflectionFunction is not really mine. It's a third party dll which i have used many times before on really large and complex classes and it is safe to assume that it works fine.
I removed each and every member variable of class A but i still get the error. " Unable to cast object of type 'MyNamespace.A' to 'MyNamespace.A' "
Code i am trying now: object obj = MyReflectionFunction("classA"); A objA = (A) obj; //Exception thrown here
What amzes me is that when I copy paste this "(A) obj" in QuickWatch or in Immediate window, the casting works!
public interface B { string Parse(string text); }
public class A: B { public A() {} public string Parse(string text) {return null;} }
Gah! This is so freaky.
GeezerButler - 02 Jun 2007 18:53 GMT > On Jun 2, 9:16 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com> > wrote: [quoted text clipped - 50 lines] > > - Show quoted text - And here's the disassembly of this line (A objA = (A) obj): Sadly i dont know what to make of it. Exception is thrown at 000001be:
000001a0 cmp dword ptr [ebp-50h],0 000001a4 je 000001C5 000001a6 mov eax,dword ptr [ebp-50h] 000001a9 cmp dword ptr [eax],3BB28C0h 000001af jne 000001B6 000001b1 mov eax,dword ptr [ebp-50h] 000001b4 jmp 000001C3 000001b6 mov edx,dword ptr [ebp-50h] 000001b9 mov ecx,3BB28C0h 000001be call 791893A4 000001c3 jmp 000001C8 000001c5 mov eax,dword ptr [ebp-50h] 000001c8 mov dword ptr [ebp-54h],eax
Peter Duniho - 02 Jun 2007 19:07 GMT > And here's the disassembly of this line (A objA = (A) obj): Sadly i > dont know what to make of it. Well, there's not much to make of it. It's the same exact code you'd see casting any reference type to any other reference type.
The code first checks for a null pointer. Null pointers can be cast to anything, so if it's null, it skips right ahead to offset 0x01c5 where the local variable gets copied to the other local variable.
If the pointer isn't null, then it compares the signature value of the instance to the constant 0x3BB28C0. If they are not equal, it jumps to the section of the code that throws the exception. If they are equal, it copies the local variable to the eax register, then does a double-jump eventually winding up at the last line where the eax register is copied to the other local variable.
(Note that the double-jump is likely because you're showing non-optimized code. Easier to read, but it includes funny things like that, that are a side-effect of the compiler allowing for more complex expressions).
The bottom line here is that there's absolutely nothing odd about the code you've posted. The compiler is doing exactly what you'd expect, and so for the exception to be thrown, there has to be something wrong with the instance the object variable references. And the only way for that to happen is for the MyReflectionFunction() to have a problem in it.
Pete
> Exception is thrown at 000001be: > [quoted text clipped - 11 lines] > 000001c5 mov eax,dword ptr [ebp-50h] > 000001c8 mov dword ptr [ebp-54h],eax Peter Duniho - 02 Jun 2007 18:56 GMT > Well MyReflectionFunction is not really mine. It's a third party dll > which i have used many times before on really large and complex > classes and it is safe to assume that it works fine. I disagree. It seems to me that in fact, it does not work and that's the crux of your problem. Surely the fact that you get an exception trying to use an object the function returns is a clear signal that it is NOT safe to assume that it works fine.
If the object returned by the function were really of class "A", you would not get an exception casting it.
I don't have a good explanation for why the debugger doesn't complain, but I do note that at least in some cases, the debugger will happily cast whatever you give it to whatever you want. I can't say I've ever seen this in the case of class instances -- seems like it's more a value-type sort of thing -- but just because the debugger doesn't complain doesn't tell me that all is well with your class instance.
If I had to guess, I'd guess that you somehow have two different class "A"s running around. I cannot fathom why this could be, but it's possible that there's something funny going on in the MyReflectionFunction() that causes that to happen. But again, without that code, it's not possible to comment on it.
There is a very small chance that someone else will take a look at this and identify the behavior and explain what's wrong. However, I think you are much more likely to get help if you can post a concise-but-complete code sample that demonstrates the problem.
Pete
Jon Skeet [C# MVP] - 02 Jun 2007 19:30 GMT > I have a class A derived from interface B. > I create object of A (using reflection) and then i try to cast the [quoted text clipped - 12 lines] > > This has me stumped now for the last few hours. Do you by any chance have B defined in multiple assemblies? If so, that would certainly explain things somewhat.
 Signature Jon Skeet - <skeet@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
GeezerButler - 02 Jun 2007 22:37 GMT > > I have a class A derived from interface B. > > I create object of A (using reflection) and then i try to cast the [quoted text clipped - 21 lines] > > - Show quoted text - Now i only have the class A. No interface B. public class A { //Completely empty }
The myReflectedFunction works like this: 1. There is an xml like this: <namespace name="MyNamespace.A"> <property name="type_name"> <value>MyNamespace.A</value> </property> <property name="assembly"> <value>..path till my project\bin\Debug\MyNamespace.dll</value> </property> </namespace> 2. I call object a = myReflectedFunction("MyNamespace.A"); This reads the type and assembly from the xml above and creates the object as follows 3. The code for creating the object is like this: Type type = Assembly.LoadFrom(assemblyName, securityAttributes).GetType(typeName, true, ignoreCase); object obj = type.GetConstructor(bindingAttr, binder, callConvention, types, modifiers). Invoke(bindingAttr, binder, parameters, culture); return obj;
When i view the type and obj in the debugger, i can see that the type is correct and the object is of correct type. Atleast it seems to me that they are correct. Infact in the step 3 mentioned above, i can debug into the ctor of A. So i can be sure that it's class A's ctor that is being called and not some other class with the same name.
So after object a = myReflectedFunction("MyNamespace.A"); this line a.GetType().Equals(typeof(MyNamespace.A) returns false!! Any idea as to how i can see why the above line returns false?
GeezerButler - 02 Jun 2007 22:48 GMT > > > I have a class A derived from interface B. > > > I create object of A (using reflection) and then i try to cast the [quoted text clipped - 64 lines] > > - Show quoted text - One correction above, ClassA is not totally empty but has a default ctor, which i think is as good is empty right?
Jon Skeet [C# MVP] - 02 Jun 2007 23:46 GMT <snip>
> 3. The code for creating the object is like this: > Type type = Assembly.LoadFrom(assemblyName, [quoted text clipped - 3 lines] > Invoke(bindingAttr, binder, parameters, culture); > return obj; Aha - so it's loading an assembly explicitly. That's likely to be relevant.
> When i view the type and obj in the debugger, i can see that the type > is correct and the object is of correct type. Atleast it seems to me > that they are correct. I suspect this is not true. At least, not when you study it in detail - see below.
> Infact in the step 3 mentioned above, i can debug into the ctor of A. > So i can be sure that it's class A's ctor that is being called and not [quoted text clipped - 5 lines] > returns false!! > Any idea as to how i can see why the above line returns false? Yes - I suspect they come from different Assembly objects. Now, I have to confess that I've never really understood *exactly* under what circumstances Assembly.LoadFrom creates a new instance of Assembly and under what circumstances it uses one which is already loaded. However, I *have* seen this kind of situation before. (In particular, I've seen a situation where a unit test gives a different result depending on which test runner is running it!)
I'm sorry not to have enough time to investigate further for you, but hopefully that will at least give you an avenue of enquiry to pursue.
 Signature Jon Skeet - <skeet@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
GeezerButler - 03 Jun 2007 00:01 GMT > > I have a class A derived from interface B. > > I create object of A (using reflection) and then i try to cast the [quoted text clipped - 21 lines] > > - Show quoted text - Jon, You always have some sort of an answer to my questions (though i dont always fully understand them) Thanks, though i did not expect the type A to be in 2 different assemblies, but that was indeed the problem. I found the differences in the Types by using The Object Comparer that i wrote a few days back, woth which you helped me too! But i am still confused about the whole thing.
Let me explain a little bit. I have 3 projects in my soln: 1. MyNamespace.dll (Dll that i am writing) 2. ObjectFactory.dll (Third party dll for creating objects dynamically) 3. ToTestIt.exe (Console application which i add to all my solutions for testing the dll that i write)
Now, the offending code
object obj = ObjectFactory.MyReflectionFunction("classA"); A objA = (A) obj; if (a.GetType().Equals(typeof(MyNamespace.A)) { throw Exception(); }
is in a function in MyClass in MyNamespace project. I call this function from the ToTestIt exe.
Now the "typeof(MyNamespace.A)" code above has 'module' as "path/ ToTestIt/bin/debug/MyNamespace.dll" and not "path/MyNamespace/bin/debug/MyNamespace.dll". I can't seem to understand why this is the case? Can you help me with this. Hope you could understand my question.
Jon Skeet [C# MVP] - 03 Jun 2007 01:07 GMT <snip>
> Let me explain a little bit. > I have 3 projects in my soln: [quoted text clipped - 3 lines] > 3. ToTestIt.exe (Console application which i add to all my solutions > for testing the dll that i write) <snip>
> Now the "typeof(MyNamespace.A)" code above has 'module' as "path/ > ToTestIt/bin/debug/MyNamespace.dll" and not > "path/MyNamespace/bin/debug/MyNamespace.dll". > I can't seem to understand why this is the case? Can you help me with > this. > Hope you could understand my question. Aha - good, this is a lot simpler than I'd previously feared then :)
When you build ToTestIt.exe, it will copy both of the other DLLs to the same output folder (at least if the Copy Local property of each reference is set to true).
When you run ToTestIt.exe, those "local" copies of the assemblies are being used. When you explicitly load a different filename, it's treating it as a different assembly - I expect!
 Signature Jon Skeet - <skeet@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
Adam Benson - 05 Jun 2007 17:05 GMT > When you run ToTestIt.exe, those "local" copies of the assemblies are > being used. When you explicitly load a different filename, it's > treating it as a different assembly - I expect! Definitely. We've had migraines over the same sort of behaviour.
The "same" object in 2 copies of the "same" dll are not the same. We had a bad deployment that put one copy of the dll in a libs directory and another copy in the exe directory. Casting failed for objects to their own type, because the code attempting the cast was being given an evil twin rather than the real thing.
Delete one of the dlls and you're OK.
- Adam. ========
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|