18
votes

Got an issue where MyObj.classnameis(TMyClass.classname) is true and TMyClass(MyObj) works but (MyObj as TMyclass).doSomething throws a conversion error.

I don't really want any help with that junk, although if you want to put it in the comments that'd be super. I just would like to know what the difference between Obj as Class and Class(Obj) is.

2
That is quite a lot of tags. I think 'delphi' would be sufficient. - Andrew
Thanks for pointing out the problem I was just pointing out - Peter Turner
Do you use DLLs? DLLs mess up class identity. - Uli Gerhardt
yeah, pretty sure it's a DLL issue. - Peter Turner
Yeah, that could be part of the problem. DLLs contain their own copy of the unit where the object is declared. The type checking works by comparing class references, which are basically VMT pointers. If the EXE and the DLL each have their own copies of the VMT, the check will fail. This raises the question, why are you passing objects in and out of a DLL? - Mason Wheeler

2 Answers

33
votes

An as-cast checks the actual object type to make sure the cast is valid, and raises an exception if it's not. A "hard cast" (TMyClass(MyObj) style) does not check, it just tells the compiler to assume the cast is valid.

If you've got a situation where ClassNameIs returns true but the as-cast fails, that means you have two different classes in two different units with the same name, and the as-cast is trying to cast to the wrong one. This also means that your hard-cast is casting to the wrong one, which could potentially lead to memory corruption.

Run a full project search for "TMyclass =" to see where your multiple declarations are, and either rename one of the classes or use a full definition (obj as MyUnit.TMyClass) so the compiler will know which class you're trying to cast to.

6
votes

Addition to Mason's post: Instead of a searching through your code, you could also call a method like this one at the location that gives you problem.

function GetClassInheritance(Obj : TObject) : string;
var ClassRef : TClass;
begin
  Result := '';
  ClassRef := obj.ClassType;
  Result := ClassRef.ClassName;
  ClassRef := ClassRef.ClassParent;
  while assigned(ClassRef) do
  begin
    Result    := ClassRef.ClassName + '.' + Result;
    ClassRef  := ClassRef.ClassParent;
  end;

  Result := '(' + obj.ClassType.UnitName + ')' + Result
end;

That will return you a string formated as (UnitName)TObject.TPersistent.TComponent.... I don't remember seeing "ClassType.UnitName" in older version of delphi, so that part might not work with them, but the rest should.