3

I have a dictionary that contains different kinds of values and I want to filter for an item that has a specific sub-type and that satisfies a certain condition:

var
  FData: IDictionary<TGUID, TObject>; // Polymorphic
begin
  TMicroStep(FData.Values.Single(
    function(const O: TObject): Boolean begin
      Result := (O is TMicroStep) and (TMicroStep(O).OrderTag = 1);
  end))
end;

It works, but it looks ugly, because of the type check and double cast.

Maybe something like this might be possible?

var
  FData: IDictionary<TGUID, TObject>; // Polymorphic
begin
  FData.Values.SingleSubType<TMicroStep>(
    function(const MS: TMicroStep): Boolean begin
      Result := MS.OrderTag = 1;
  end))
end;

Does Spring have anything that can help me here?

Jens Mühlenhoff
  • 14,565
  • 6
  • 56
  • 113

1 Answers1

4

Unfortunately Delphi does not support parameterized methods in interfaces. That is why IEnumerable<T> does not have methods like OfType<TResult>.

You could use a static method like we provide in TCollections (or with 1.2 in the new static type TEnumerable that provides those methods) but I don't know if you like that any better than what you already have:

TEnumerable.OfType<TObject, TMicroStep>(FData.Values).Single(
  function(const MS: TMicroStep): Boolean
  begin
    Result := MS.OrderTag = 1;
  end);

The method would look like this (untested but should work):

class function TEnumerable.OfType<T, TResult>(
  const source: IEnumerable<T>): IEnumerable<TResult>;
begin
  Result := TOfTypeIterator<T, TResult>.Create(source);
end;

TOfTypeIterator<T,TResult> is from Spring.Collections.Extensions.

The type check in its MoveNext method certainly can be improved when dealing with classes to avoid TValue.

Stefan Glienke
  • 20,860
  • 2
  • 48
  • 102