14

As we all known, when we call a constructor of a class like this:

instance := TSomeClass.Create;

The Delphi compiler actually do the following things:

  1. Call the static NewInstance method to allocate memory and initialize the memory layout.
  2. Call the constructor method to perform the initialization of the class
  3. Call the AfterConstruction method

It's simple and easy to understand. but I'm not very sure how the compiler handle exceptions in the second and the third step.

It seems there are no explicit way to create an instance using a RTTI constructor method in D2010. so I wrote a simple function in the Spring Framework for Delphi to reproduce the process of the creation.

class function TActivator.CreateInstance(instanceType: TRttiInstanceType;
  constructorMethod: TRttiMethod; const arguments: array of TValue): TObject;
var
  classType: TClass;
begin
  TArgument.CheckNotNull(instanceType, 'instanceType');
  TArgument.CheckNotNull(constructorMethod, 'constructorMethod');
  classType := instanceType.MetaclassType;
  Result := classType.NewInstance;
  try
    constructorMethod.Invoke(Result, arguments);
  except
    on Exception do
    begin
      if Result is TInterfacedObject then
      begin
        Dec(TInterfacedObjectHack(Result).FRefCount);
      end;
      Result.Free;
      raise;
    end;
  end;
  try
    Result.AfterConstruction;
  except
    on Exception do
    begin
      Result.Free;
      raise;
    end;
  end;
end;

I feel it maybe not 100% right. so please show me the way. Thanks!

Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
Baoquan Zuo
  • 652
  • 4
  • 15

1 Answers1

18

Invoking the constructor and passing the class as the Self argument (as opposed to an instance) will correctly construct the class. The process of constructing includes the NewInstance, AfterConstruction etc. that you are manually doing here: it's not necessary.

This ought to be sufficient:

Result := constructorMethod.Invoke(instanceType.MetaclassType, arguments);

An oddity of Delphi is how it permits constructors to be called on instances as well as classes. This feature is used as a kind of "placement new" (in C++ terminology) for form construction, so that the global form variable (e.g. Form1 by default for the first form) is assigned at the time that the OnCreate constructor gets invoked. Thus, your code doesn't raise an exception. But it is more normal to pass the class rather than the instance as the Self argument.

Barry Kelly
  • 41,404
  • 5
  • 117
  • 189
  • Thank you so much! I finally got why there are an overload of the Invoke with a class parameter. – Baoquan Zuo Jun 18 '10 at 11:17
  • @Paul: That overload can also be used to call **class** methods. – Mason Wheeler Jun 18 '10 at 12:26
  • Yeah. But I was confused by the name of the parameter. (Instance: TClass...) – Baoquan Zuo Jun 29 '10 at 01:05
  • I think I may have found a situation where you need to pass the instance to the constructor as self. In my situation the invoked constructor uses Rtti as well to populate its fields. When passing the class as self the invoked constructor does not have a valid self reference to pass to RttiField.SetValue. Invoking the constructor with the instance as self fixes this. – monoceres Feb 10 '14 at 11:06