Delphi: Использование перечисленных перечислений для фильтрации TLIST по типу класса?

StackOverflow https://stackoverflow.com/questions/2740787

Вопрос

Хорошо, это может быть запутано. То, что я пытаюсь сделать, это использовать перечислетель, чтобы вернуть только определенные элементы в универсальном списке на основе типа класса.

Учитывая следующую иерархию:

type
    TShapeClass = class of TShape;

    TShape = class(TObject)
    private
        FId: Integer;
    public
        function ToString: string; override;
        property Id: Integer read FId write FId;
    end;

    TCircle = class(TShape)
    private
        FDiameter: Integer;
    public
        property Diameter: Integer read FDiameter write FDiameter;
    end;

    TSquare = class(TShape)
    private
        FSideLength: Integer;
    public
        property SideLength: Integer read FSideLength write FSideLength;
    end;

    TShapeList = class(TObjectList<TShape>)
    end;

Как я могу продлить TShapeList Такое, что я могу сделать что-то похожее на следующее:

procedure Foo;
var
    ShapeList: TShapeList;
    Shape: TShape;
    Circle: TCircle;
    Square: TSquare;

begin
    // Create ShapeList and fill with TCircles and TSquares
    for Circle in ShapeList<TCircle> do begin
        // do something with each TCircle in ShapeList
    end;
    for Square in ShapeList<TSquare> do begin
        // do something with each TSquare in ShapeList
    end;
    for Shape in ShapeList<TShape> do begin
        // do something with every object in TShapeList
    end;
end;

Я пытался простираться TShapeList Использование адаптированной версии примосного габрийзельчика Параметризованные перечислители Использование заводской записи следующим образом:

type
    TShapeList = class(TObjectList<TShape>)
    public
        type
            TShapeFilterEnumerator<T: TShape> = record
            private
                FShapeList: TShapeList;
                FClass: TShapeClass;
                FIndex: Integer;
                function GetCurrent: T;
            public
                constructor Create(ShapeList: TShapeList);
                function MoveNext: Boolean;
                property Current: T read GetCurrent;
            end;

            TShapeFilterFactory<T: TShape> = record
            private
                FShapeList: TShapeList;
            public
                constructor Create(ShapeList: TShapeList);
                function GetEnumerator: TShapeFilterEnumerator<T>;
            end;

        function FilteredEnumerator<T: TShape>: TShapeFilterFactory<T>;
    end;

Тогда я изменил Foo быть:

procedure Foo;
var
    ShapeList: TShapeList;
    Shape: TShape;
    Circle: TCircle;
    Square: TSquare;

begin
    // Create ShapeList and fill with TCircles and TSquares
    for Circle in ShapeList.FilteredEnumerator<TCircle> do begin
        // do something with each TCircle in ShapeList
    end;
    for Square in ShapeList.FilteredEnumerator<TSquare> do begin
        // do something with each TSquare in ShapeList
    end;
    for Shape in ShapeList.FilteredEnumerator<TShape> do begin
        // do something with every object in TShapeList
    end;
end;

Тем не менее, Delphi 2010 бросает ошибку, когда я пытаюсь компилировать Foo о Incompatible types: TCircle and TShape. Отказ Если я прокомментирую TCircle петля, тогда я получаю подобную ошибку о TSquare. Отказ Если я комментирую TSquare Выйдите также, код компилирует и работает. Ну, это работает в том смысле, что он перечисляет каждый объект, так как все они спускаются от TShape. Отказ Странная вещь состоит в том, что номер строки, что компилятор указывает, составляет 2 строки за конец моего файла. В моем демонстрационном проекте он указал линию 177, но есть только 175 строк.

Есть ли способ сделать эту работу? Я хотел бы иметь возможность присвоить кружок напрямую, не проходя через какие-либо текстуры или проверку в моем for сам петля.

Это было полезно?

Решение

Вы не показываете это здесь, но проблема, вероятно, заключается в реализации GetCurrent.

Пока компилятор принимает что-то вроде

result := FShapeList[FIndex];

В общем классе это не удастся, когда класс результата не равен TSHape, который имеет место для Ткси и ЦККАРА. Отказ Вот почему он работает в третьей петле.

Изменить код в

result := T(FShapeList[FIndex]);

И ты в порядке.

Не существующий номер строки для ошибки связан с разрешением внутреннего универсального образования компилятором, который не хорошо отображается номерам строк.

Другие советы

Вы не можете сделать это непосредственно в перечислении. Боюсь, ты застрял с "-". Единственный путь действительно создает некоторой помощника перечисления. В вашем случае попробуйте комментировать строки, пока не найдете единственное, что делает компилятор несчастной.

Извините, что это совсем все, что я могу предложить.

Вы написали ответ в вашем вопросе :)

Вам просто нужно позвонить правильную функцию:

for Circle in ShapeList.FilteredEnumerator<TCircle> do
  //blah blah

for Square in ShapeList.FilteredEnumerator<TSquare> do
  //blah blah

Одно маленькое замечание о вашем коде: вы можете бросить свой TShapeFilterFactory Запись, и просто добавьте метод:

TShapeFilterEnumerator<T>.GetEnumerator : TShapeFilterEnumerator<T>;
begin
  Result := Self;
end;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top