unit Myc.Data.Types.Method; interface uses System.SysUtils, System.Generics.Collections, Myc.Data.Types; type // Implements the IDataMethodType interface. TImplDataMethodType = class(TInterfacedObject, IDataMethodType) strict private // Class-level registry to cache and reuse method type definitions. class var FMethodTypeRegistry: TDictionary, IDataMethodType>; private FArgType: IDataType; FResultType: IDataType; function GetName: String; function GetKind: TDataKind; function GetArgType: IDataType; function GetResultType: IDataType; function CreateValue(const AValue: TDataMethodProc): IDataMethodValue; public constructor Create(const AArgType, AResultType: IDataType); class constructor CreateClass; class destructor DestroyClass; // Factory method to get a cached or new method type instance. class function GetInstance(const AArgType, AResultType: IDataType): IDataMethodType; static; end; implementation uses System.Classes, System.SyncObjs, System.Generics.Defaults; type // Implements the IDataMethodValue interface. TImplDataMethodValue = class(TInterfacedObject, IDataMethodValue) private FDataType: IDataMethodType; FValue: TDataMethodProc; function GetDataType: IDataType; function GetAsString: string; function GetValue: TDataMethodProc; public constructor Create(const ADataType: IDataMethodType; const AValue: TDataMethodProc); end; { TImplDataMethodType } class constructor TImplDataMethodType.CreateClass; begin // Initialize the global registry for method types using a custom comparer for the TPair key. FMethodTypeRegistry := TDictionary, IDataMethodType>.Create( TEqualityComparer>.Construct( function(const Left, Right: TPair): Boolean begin // Compare interface pointers. Result := (Left.Key = Right.Key) and (Left.Value = Right.Value); end, function(const Value: TPair): Integer var hash1, hash2: NativeInt; begin // Combine hashes of interface pointers. hash1 := NativeInt(Value.Key); hash2 := NativeInt(Value.Value); Result := Integer(hash1 xor hash2); end ) ); end; class destructor TImplDataMethodType.DestroyClass; begin FMethodTypeRegistry.Free; FMethodTypeRegistry := nil; end; class function TImplDataMethodType.GetInstance(const AArgType, AResultType: IDataType): IDataMethodType; var key: TPair; res: IDataMethodType; begin key := TPair.Create(AArgType, AResultType); TMonitor.Enter(FMethodTypeRegistry); try if not FMethodTypeRegistry.TryGetValue(key, res) then begin res := TImplDataMethodType.Create(AArgType, AResultType); FMethodTypeRegistry.Add(key, res); end; finally TMonitor.Exit(FMethodTypeRegistry); end; Result := res; end; constructor TImplDataMethodType.Create(const AArgType, AResultType: IDataType); begin inherited Create; FArgType := AArgType; FResultType := AResultType; end; function TImplDataMethodType.CreateValue(const AValue: TDataMethodProc): IDataMethodValue; begin Assert(Assigned(AValue)); Result := TImplDataMethodValue.Create(Self, AValue); end; function TImplDataMethodType.GetArgType: IDataType; begin Result := FArgType; end; function TImplDataMethodType.GetResultType: IDataType; begin Result := FResultType; end; function TImplDataMethodType.GetKind: TDataKind; begin Result := dkMethod; end; function TImplDataMethodType.GetName: String; var sb: TStringBuilder; argName, resultName: string; begin if Assigned(FArgType) then argName := FArgType.Name else argName := 'Void'; if Assigned(FResultType) then resultName := FResultType.Name else resultName := 'Void'; sb := TStringBuilder.Create; try sb.Append('Method<'); sb.Append(argName); sb.Append(' -> '); sb.Append(resultName); sb.Append('>'); Result := sb.ToString; finally sb.Free; end; end; { TImplDataMethodValue } constructor TImplDataMethodValue.Create(const ADataType: IDataMethodType; const AValue: TDataMethodProc); begin inherited Create; FDataType := ADataType; FValue := AValue; end; function TImplDataMethodValue.GetDataType: IDataType; begin Result := FDataType; end; function TImplDataMethodValue.GetAsString: string; begin Result := ''; end; function TImplDataMethodValue.GetValue: TDataMethodProc; begin Result := FValue; end; end.