返回属性值的类的Delphi静态方法
我正在制作一个Delphi VCL应用程序。有一个类TStudent,其中我有两个静态函数:一个从TStudent数组返回姓氏,另一个返回学生的名字。他们的代码类似于:返回属性值的类的Delphi静态方法,delphi,properties,static-methods,Delphi,Properties,Static Methods,我正在制作一个Delphi VCL应用程序。有一个类TStudent,其中我有两个静态函数:一个从TStudent数组返回姓氏,另一个返回学生的名字。他们的代码类似于: class function TStudent.FirstNameOf(aLastName: string): string; var i : integer; begin for i := 0 to Length(studentsArray) - 1 do begin if studentsArray[i].Las
class function TStudent.FirstNameOf(aLastName: string): string;
var i : integer;
begin
for i := 0 to Length(studentsArray) - 1 do begin
if studentsArray[i].LastName = aLastName then
begin
result := studentsArray[i].FirstName;
Exit;
end;
end;
result := 'no match was found';
end;
class function TStudent.LastNameOf(aFirstName: string): string;
var i : integer;
begin
for i := 0 to Length(studentsArray) - 1 do begin
if studentsArray[i].FirstName = aFirstName then
begin
result := studentsArray[i].LastName;
Exit;
end;
end;
result := 'no match was found';
end;
我的问题是如何避免几乎相同的代码编写两次。是否有任何方法可以将属性作为函数的参数传递。对于此线性搜索,可以使用带有变量捕获的匿名方法。这种方法使谓词具有完全的通用性。您可以测试任何类型的任何字段是否相等。您可以测试更复杂的谓词,例如非此即彼或检查 代码可能如下所示:
class function TStudent.LinearSearch(const IsMatch: TPredicate<TStudent>;
out Index: Integer): Boolean;
var
i: Integer;
begin
for i := low(studentsArray) to high(studentsArray) do
begin
if IsMatch(studentsArray[i]) then
begin
Index := i;
Result := True;
exit;
end;
end;
Index := -1;
Result := False;
end;
class function TStudent.GetFirstName(const LastName: string): string;
var
Index: Integer;
IsMatch: TPredicate<TStudent>;
begin
IsMatch :=
function(Student: TStudent): Boolean
begin
Result := Student.LastName=LastName;
end;
if not LinearSearch(IsMatch, Index) then
begin
raise ...
end;
Result := studentsArray[Index].FirstName;
end;
FirstName := TStudent.GetNameOf('LastName', 'Smoe', 'FirstName');
因此,您可以这样编写方法:
class function TStudent.LinearSearch(const IsMatch: TPredicate<TStudent>;
out Index: Integer): Boolean;
var
i: Integer;
begin
for i := low(studentsArray) to high(studentsArray) do
begin
if IsMatch(studentsArray[i]) then
begin
Index := i;
Result := True;
exit;
end;
end;
Index := -1;
Result := False;
end;
class function TStudent.GetFirstName(const LastName: string): string;
var
Index: Integer;
IsMatch: TPredicate<TStudent>;
begin
IsMatch :=
function(Student: TStudent): Boolean
begin
Result := Student.LastName=LastName;
end;
if not LinearSearch(IsMatch, Index) then
begin
raise ...
end;
Result := studentsArray[Index].FirstName;
end;
FirstName := TStudent.GetNameOf('LastName', 'Smoe', 'FirstName');
类函数TStudent.GetFirstName(constlastname:string):string;
变量
索引:整数;
IsMatch:t预测;
开始
IsMatch:=
函数(学生:TStudent):布尔值
开始
结果:=Student.LastName=LastName;
终止
如果不是线性搜索(IsMatch,索引),则
开始
提升
终止
结果:=studentsArray[Index].FirstName;
终止
同样,对于GetLastName
如果您的Delphi不支持匿名方法,那么您将无法使用变量捕获,并且必须使用对象的
方法类型找到更复杂的方法。但是,基本思路基本相同。您可以使用带有变量捕获的匿名方法进行此线性搜索。这种方法使谓词具有完全的通用性。您可以测试任何类型的任何字段是否相等。您可以测试更复杂的谓词,例如非此即彼或检查
代码可能如下所示:
class function TStudent.LinearSearch(const IsMatch: TPredicate<TStudent>;
out Index: Integer): Boolean;
var
i: Integer;
begin
for i := low(studentsArray) to high(studentsArray) do
begin
if IsMatch(studentsArray[i]) then
begin
Index := i;
Result := True;
exit;
end;
end;
Index := -1;
Result := False;
end;
class function TStudent.GetFirstName(const LastName: string): string;
var
Index: Integer;
IsMatch: TPredicate<TStudent>;
begin
IsMatch :=
function(Student: TStudent): Boolean
begin
Result := Student.LastName=LastName;
end;
if not LinearSearch(IsMatch, Index) then
begin
raise ...
end;
Result := studentsArray[Index].FirstName;
end;
FirstName := TStudent.GetNameOf('LastName', 'Smoe', 'FirstName');
因此,您可以这样编写方法:
class function TStudent.LinearSearch(const IsMatch: TPredicate<TStudent>;
out Index: Integer): Boolean;
var
i: Integer;
begin
for i := low(studentsArray) to high(studentsArray) do
begin
if IsMatch(studentsArray[i]) then
begin
Index := i;
Result := True;
exit;
end;
end;
Index := -1;
Result := False;
end;
class function TStudent.GetFirstName(const LastName: string): string;
var
Index: Integer;
IsMatch: TPredicate<TStudent>;
begin
IsMatch :=
function(Student: TStudent): Boolean
begin
Result := Student.LastName=LastName;
end;
if not LinearSearch(IsMatch, Index) then
begin
raise ...
end;
Result := studentsArray[Index].FirstName;
end;
FirstName := TStudent.GetNameOf('LastName', 'Smoe', 'FirstName');
类函数TStudent.GetFirstName(constlastname:string):string;
变量
索引:整数;
IsMatch:t预测;
开始
IsMatch:=
函数(学生:TStudent):布尔值
开始
结果:=Student.LastName=LastName;
终止
如果不是线性搜索(IsMatch,索引),则
开始
提升
终止
结果:=studentsArray[Index].FirstName;
终止
同样,对于GetLastName
如果您的Delphi不支持匿名方法,那么您将无法使用变量捕获,并且必须使用对象的方法类型找到更复杂的方法。不过,基本思路大致相同。我还没有测试过,但我相信这可能是一个解决方案
uses TypInfo;
class function TStudent.GetProperty( propertyName: string, searchValue : Variant ) : Variant ;
var i : integer;
begin
for i := 0 to Length(studentsArray) - 1 do begin
if GetPropValue( studentsArray[i], propertyName ) = searchValue
result := GetPropValue( studentsArray[i], propertyName );
end;
// your code in case of not finding anything
end;
我还没有测试过,但我相信这可能是一个解决方案
uses TypInfo;
class function TStudent.GetProperty( propertyName: string, searchValue : Variant ) : Variant ;
var i : integer;
begin
for i := 0 to Length(studentsArray) - 1 do begin
if GetPropValue( studentsArray[i], propertyName ) = searchValue
result := GetPropValue( studentsArray[i], propertyName );
end;
// your code in case of not finding anything
end;
与常规数组属性一样,您可以将多个属性与由单个getter函数支持的索引说明符一起使用:
TDefault = class(TObject)
private
class function GetProp(const FindWhat: string; FindWhere: Integer): string;
static;
protected
/// <remarks>
/// You don't really need this one. I've added it for an illustration
/// purposes.
/// </remarks>
class property Prop[const FindWhat: string; FindWhere: Integer]: string read GetProp;
public
class property A[const FindWhat: string]: string index 0 read GetProp;
class property B[const FindWhat: string]: string index 1 read GetProp;
end;
{ ... }
class function TDefault.GetProp(const FindWhat: string; FindWhere: Integer): string;
begin
case FindWhere of
0: Result := 'Hallo!';
1: Result := 'Hello!';
end;
Result := Result + ' ' + Format('searching for "%s"', [FindWhat]);
end;
TDefault=class(TObject)
私有的
类函数GetProp(const FindWhat:string;FindWhere:Integer):string;
静止的
受保护的
///
///你真的不需要这个。我加上它是为了举例说明
///目的。
///
类属性Prop[const FindWhat:string;FindWhere:Integer]:string read GetProp;
平民的
类属性A[const FindWhat:string]:字符串索引0读取GetProp;
类属性B[const FindWhat:string]:字符串索引1读取GetProp;
终止
{ ... }
类函数TDefault.GetProp(const FindWhat:string;FindWhere:Integer):string;
开始
在哪里找到的案例
0:结果:='Hallo!';
1:结果:=“你好!”;
终止
结果:=结果+“”+格式('搜索“%s”,[FindWhat]);
终止
如您所见,类属性与实例属性完全相同
我必须说,在属性getter中执行搜索是一个非常糟糕的主意。您可以使用带有索引的多个属性
说明符,由单个getter函数支持,就像您对常规数组属性所做的那样:
TDefault = class(TObject)
private
class function GetProp(const FindWhat: string; FindWhere: Integer): string;
static;
protected
/// <remarks>
/// You don't really need this one. I've added it for an illustration
/// purposes.
/// </remarks>
class property Prop[const FindWhat: string; FindWhere: Integer]: string read GetProp;
public
class property A[const FindWhat: string]: string index 0 read GetProp;
class property B[const FindWhat: string]: string index 1 read GetProp;
end;
{ ... }
class function TDefault.GetProp(const FindWhat: string; FindWhere: Integer): string;
begin
case FindWhere of
0: Result := 'Hallo!';
1: Result := 'Hello!';
end;
Result := Result + ' ' + Format('searching for "%s"', [FindWhat]);
end;
TDefault=class(TObject)
私有的
类函数GetProp(const FindWhat:string;FindWhere:Integer):string;
静止的
受保护的
///
///你真的不需要这个。我加上它是为了举例说明
///目的。
///
类属性Prop[const FindWhat:string;FindWhere:Integer]:string read GetProp;
平民的
类属性A[const FindWhat:string]:字符串索引0读取GetProp;
类属性B[const FindWhat:string]:字符串索引1读取GetProp;
终止
{ ... }
类函数TDefault.GetProp(const FindWhat:string;FindWhere:Integer):string;
开始
在哪里找到的案例
0:结果:='Hallo!';
1:结果:=“你好!”;
终止
结果:=结果+“”+格式('搜索“%s”,[FindWhat]);
终止
如您所见,类属性与实例属性完全相同
我必须说,在属性getter中执行搜索是一个非常糟糕的主意。如果您使用的是Delphi 2010或更高版本,您可以使用扩展RTTI:
uses
..., Rtti;
type
TStudent = class
public
FirstName: String;
LastName: String;
class function GetNameOf(const aFieldToFind, aNameToFind, aFieldToReturn: string): string;
end;
class function TStudent.GetNameOf(const aFieldToFind, aNameToFind, aFieldToReturn: string): string;
var
i : integer;
ctx: TRttiContent;
StudentType: TRttiType;
Field: TRttiField;
Value: TValue;
begin
ctx := TRttiContext.Create;
StudentType := ctx.GetType(TStudent);
Field := StudentType.GetField(aFieldToFind);
for i := 0 to Length(studentsArray) - 1 do
begin
if Field.GetValue(@studentsArray[i]).AsString = aNameToFind then
begin
Result := StudentType.GetField(aFieldToReturn).GetValue(@studentsArray[i]).AsString;
Exit;
end;
end;
Result := 'no match was found';
end;
然后你可以这样称呼它:
class function TStudent.LinearSearch(const IsMatch: TPredicate<TStudent>;
out Index: Integer): Boolean;
var
i: Integer;
begin
for i := low(studentsArray) to high(studentsArray) do
begin
if IsMatch(studentsArray[i]) then
begin
Index := i;
Result := True;
exit;
end;
end;
Index := -1;
Result := False;
end;
class function TStudent.GetFirstName(const LastName: string): string;
var
Index: Integer;
IsMatch: TPredicate<TStudent>;
begin
IsMatch :=
function(Student: TStudent): Boolean
begin
Result := Student.LastName=LastName;
end;
if not LinearSearch(IsMatch, Index) then
begin
raise ...
end;
Result := studentsArray[Index].FirstName;
end;
FirstName := TStudent.GetNameOf('LastName', 'Smoe', 'FirstName');
如果您使用的是Delphi 2010或更高版本,则可以使用扩展RTTI:
uses
..., Rtti;
type
TStudent = class
public
FirstName: String;
LastName: String;
class function GetNameOf(const aFieldToFind, aNameToFind, aFieldToReturn: string): string;
end;
class function TStudent.GetNameOf(const aFieldToFind, aNameToFind, aFieldToReturn: string): string;
var
i : integer;
ctx: TRttiContent;
StudentType: TRttiType;
Field: TRttiField;
Value: TValue;
begin
ctx := TRttiContext.Create;
StudentType := ctx.GetType(TStudent);
Field := StudentType.GetField(aFieldToFind);
for i := 0 to Length(studentsArray) - 1 do
begin
if Field.GetValue(@studentsArray[i]).AsString = aNameToFind then
begin
Result := StudentType.GetField(aFieldToReturn).GetValue(@studentsArray[i]).AsString;
Exit;
end;
end;
Result := 'no match was found';
end;
然后你可以这样称呼它:
class function TStudent.LinearSearch(const IsMatch: TPredicate<TStudent>;
out Index: Integer): Boolean;
var
i: Integer;
begin
for i := low(studentsArray) to high(studentsArray) do
begin
if IsMatch(studentsArray[i]) then
begin
Index := i;
Result := True;
exit;
end;
end;
Index := -1;
Result := False;
end;
class function TStudent.GetFirstName(const LastName: string): string;
var
Index: Integer;
IsMatch: TPredicate<TStudent>;
begin
IsMatch :=
function(Student: TStudent): Boolean
begin
Result := Student.LastName=LastName;
end;
if not LinearSearch(IsMatch, Index) then
begin
raise ...
end;
Result := studentsArray[Index].FirstName;
end;
FirstName := TStudent.GetNameOf('LastName', 'Smoe', 'FirstName');
如果您对t学生
记录进行一点重组,一切都会变得简单。与其有多个名称不同的字符串字段,不如声明具有枚举范围的字符串数组
为枚举指定有意义的名称,并添加一个搜索函数,可在其中指定搜索字段和结果字段
Type
TStudentField = (sfFirstName,sfLastName); // Helper enumeration type
TStudent = record
Field: array[TStudentField] of String;
class function SearchNameOf(searchField: TStudentField;
const aSearchName: string; resultField: TStudentField): string; static;
end;
下面是一个测试示例:
program ProjectTest;
{$APPTYPE CONSOLE}
Type
TStudentField = (sfFirstName,sfLastName);
TStudent = record
Field: array[TStudentField] of String;
class function SearchNameOf(searchField: TStudentField; const aSearchName: string; resultField: TStudentField): string; static;
end;
var
studentsArray : array of TStudent;
class function TStudent.SearchNameOf(searchField: TStudentField; const aSearchName: string; resultField: TStudentField): string;
var
i : integer;
begin
for i := 0 to Length(studentsArray) - 1 do begin
if (studentsArray[i].Field[searchField] = aSearchName) then
begin
Result := studentsArray[i].Field[resultField];
Exit;
end;
end;
result := 'no match was found';
end;
begin
SetLength(studentsArray,2);
studentsArray[0].Field[sfFirstName] := 'Buzz';
studentsArray[0].Field[sfLastName] := 'Aldrin';
studentsArray[1].Field[sfFirstName] := 'Neil';
studentsArray[1].Field[sfLastName] := 'Armstrong';
WriteLn(TStudent.SearchNameOf(sfFirstName,'Neil',sfLastName));
ReadLn;
end.
如果您对t学生
记录进行一点重组,一切都会变得简单。与其有多个名称不同的字符串字段,不如声明具有枚举范围的字符串数组
为枚举指定有意义的名称,并添加一个搜索函数,可在其中指定搜索字段和结果字段
Type
TStudentField = (sfFirstName,sfLastName); // Helper enumeration type
TStudent = record
Field: array[TStudentField] of String;
class function SearchNameOf(searchField: TStudentField;
const aSearchName: string; resultField: TStudentField): string; static;
end;
下面是一个测试示例:
program ProjectTest;
{$APPTYPE CONSOLE}
Type
TStudentField = (sfFirstName,sfLastName);
TStudent = record
Field: array[TStudentField] of String;
class function SearchNameOf(searchField: TStudentField; const aSearchName: string; resultField: TStudentField): string; static;
end;
var
studentsArray : array of TStudent;
class function TStudent.SearchNameOf(searchField: TStudentField; const aSearchName: string; resultField: TStudentField): string;
var
i : integer;
begin
for i := 0 to Length(studentsArray) - 1 do begin
if (studentsArray[i].Field[searchField] = aSearchName) then
begin
Result := studentsArray[i].Field[resultField];
Exit;
end;
end;
result := 'no match was found';
end;
begin
SetLength(studentsArray,2);
studentsArray[0].Field[sfFirstName] := 'Buzz';
studentsArray[0].Field[sfLastName] := 'Aldrin';
studentsArray[1].Field[sfFirstName] := 'Neil';
studentsArray[1].Field[sfLastName] := 'Armstrong';
WriteLn(TStudent.SearchNameOf(sfFirstName,'Neil',sfLastName));
ReadLn;
end.
您如何知道在使用这些函数时将返回哪个学生的姓名?为什么要硬编码要查找的姓名以及重复的姓名呢?我有一个