Those constructors are not available in the Exception class, so I tried writing an extension class for it, like so:
type
PResStringRec = ^String;
ExceptionExtension = public extension class(Exception)
public
method CreateRes(AResourceString: PResStringRec): Exception; static;
begin
self.GetType().GetConstructor(typeOf(String)).Invoke(new Object[](AResourceString^));
end;
end;
Alas, this does not compile as it tells me I cannot access non static member GetType. The idea being this construct was to create an instance of the real class, not just a Exception object.
rightfully so. I don’t think this is feasible, as static method are not polymorphic, so the method has no access to knowing that the “actual type” you called it on is.
Your best option would be declaring an actual constructor (which you can do in extensions, too), but I;'m not even sure that that would work. This might need virtual constructors (which we support in combination with “class of” class references, or it might even need additional compiler support to get right at all.
I’ll need to defer this to Carlo to answer next week.
I assume Olivier wants to create a more concrete type, ie MySpecialException.CreateRes should create a MySpecialException instance. Else he would’t need the type magic at all and could just do new Exception in there.
My gut feeling here this that this will need additional compiler support, to work in extensions (if feasible at all). I’ll log an issue and discuss it with Carlo next week,
We do support .Create* constrictor names, int Delphi Compatibility Mode, but I mist admit i’m fuzzy on what exactly the scope of that is, as I never used it myself.
No need to assign the result?
When I wrote it here, I had this:
class method CreateRes(AResourceString: PResStringRec): Exception; static; inline;
begin
result := typeOf(self).GetConstructor([typeOf(String)]).Invoke([AResourceString^]);
end;
But it rightfully complained that Object cannot be assigned to Exception. Before casting I was wondering why result is not assigned in your example. Is it because of the inline keyword?
Good question; I don’t think we have this exposed for constructors with parameters yet.
There’s:
method Instantiate<T>: Object; where T is ILifetimeStrategy<T>; // Creates a new instance of this type and calls the default constructor, fails if none is present!
begin
var lCtor: MethodInfo := Methods.FirstOrDefault(a -> (MethodFlags.Constructor in a.Flags) and (not a.Arguments.Any) and (not a.IsStatic));
if lCtor = nil then raise new Exception('No default constructor could be found on type '+Name);
var lRealCtor := CtorHelper(lCtor.Pointer);
if lRealCtor = nil then raise new Exception('No default constructor could be found!');
result := InternalCalls.Cast<Object>(T.New(fValue, SizeOfType));
lRealCtor(result);
end;
method Instantiate: Object; // Creates a new instance of this type and calls the default constructor, fails if none is present!
begin
exit Instantiate<DefaultGC>();
end;
On type, which does this for parameterless constructors.
I think
var aTypeDef := typeof(self);
var lMethodInfoForConstructor := aTypeDef.Methods.FirstOrDefault(a -> (MethodFlags.Constructor in a.Flags) and (a.Arguments.Count = 1) and (a.Arguments[0].TypeCode = TypeCodes.String) and (not a.IsStatic));
lMethodInfoForConstructor.Invoke(DefaultGC.New(aTypeDef.RTTI, aTypeDef.SizeOfType), [arguments])
should work.
I would put the typeof() in the inline method, and the complex logic in a non inlined method, for speed purposes.