寻找一个delphi库或代码片段,将为我做深度对象比较,最好是基于RTTI的,因为我的对象不会从TComponent继承。有谁知道我在哪里可以找到一个,我正在开发一个测试框架在DUnit,并需要一些固体,它会指出究竟哪个字段导致问题(序列化比较离开它有点模糊)。深度对象比较Delphi
干杯,
巴里
寻找一个delphi库或代码片段,将为我做深度对象比较,最好是基于RTTI的,因为我的对象不会从TComponent继承。有谁知道我在哪里可以找到一个,我正在开发一个测试框架在DUnit,并需要一些固体,它会指出究竟哪个字段导致问题(序列化比较离开它有点模糊)。深度对象比较Delphi
干杯,
巴里
解决这个问题的种类,作为TObject的类助手实现,所以如果人们需要它可以随处使用。 D2010和以上,因为RTTI,但你可能能够将其转换为使用原始RTTI的东西。
下面的代码可能是错误的,因为我原来是用于DUnit的,它有很多检查,而不是改变结果,不支持TCollections或其他特殊情况的负载,但可以通过使用if -elseif - 然后在中间切换。
如果您有任何建议和补充,请不要犹豫,以便我可以添加它,以便其他人可以使用它。
玩得开心编码
巴里
unit TObjectHelpers;
interface
uses classes, rtti;
type
TObjectHelpers = class Helper for TObject
function DeepEquals (const aObject : TObject) : boolean;
end;
implementation
uses sysutils, typinfo;
{ TObjectHelpers }
function TObjectHelpers.DeepEquals(const aObject: TObject): boolean;
var
c : TRttiContext;
t : TRttiType;
p : TRttiProperty;
begin
result := true;
if self = aObject then
exit; // Equal as same pointer
if (self = nil) and (aObject = nil) then
exit; // equal as both non instanced
if (self = nil) and (aObject <> nil) then
begin
result := false;
exit; // one nil other non nil fail
end;
if (self <> nil) and (aObject = nil) then
begin
result := false;
exit; // one nil other non nil fail
end;
if self.ClassType <> aObject.ClassType then
begin
result := false;
exit;
end;
c := TRttiContext.Create;
try
t := c.GetType(aObject.ClassType);
for p in t.GetProperties do
begin
if ((p.GetValue(self).IsObject)) then
begin
if not TObject(p.GetValue(self).AsObject).DeepEquals(TObject(p.GetValue(aObject).AsObject)) then
begin
result := false;
exit;
end;
end
else if AnsiSameText(p.PropertyType.Name, 'DateTime') or AnsiSameText(p.PropertyType.Name, 'TDateTime') then
begin
if p.GetValue(self).AsExtended <> p.GetValue(aObject).AsExtended then
begin
result := false;
exit;
end;
end
else if AnsiSameText(p.PropertyType.Name, 'Boolean') then
begin
if p.GetValue(self).AsBoolean <> p.GetValue(aObject).AsBoolean then
begin
result := false;
exit;
end;
end
else if AnsiSameText(p.PropertyType.Name, 'Currency') then
begin
if p.GetValue(self).AsExtended <> p.GetValue(aObject).AsExtended then
begin
result := false;
exit;
end;
end
else if p.PropertyType.TypeKind = tkInteger then
begin
if p.GetValue(self).AsInteger <> p.GetValue(aObject).AsInteger then
begin
result := false;
exit;
end;
end
else if p.PropertyType.TypeKind = tkInt64 then
begin
if p.GetValue(self).AsInt64 <> p.GetValue(aObject).AsInt64 then
begin
result := false;
exit;
end;
end
else if p.PropertyType.TypeKind = tkEnumeration then
begin
if p.GetValue(self).AsOrdinal <> p.GetValue(aObject).AsOrdinal then
begin
result := false;
exit;
end;
end
else
begin
if p.GetValue(self).AsVariant <> p.GetValue(aObject).AsVariant then
begin
result := false;
exit;
end;
end;
end;
finally
c.Free;
end;
end;
end.
非显着差异与显着差异如何? (例子:你是否曾经想过忽略窗口句柄值等差异的情况?你可以添加一个排除属性,以便深入比较可以跳过一些东西吗? –
当有人对你的类型进行类型重定义时, –
或者如果人们已经在使用他们自己的(或别人的)类助手来处理TObject,那么可以使用NOWHERE。对于大声喊叫,人们什么时候会停止使用类助手来处理那些单元级别的函数/程序足够好,而且更合理!!它确实看起来好像人们非常渴望为班级助手找到一个合法的用途,他们会在每个问题上抛出它们 - 其中99%是他们 – Deltics
考虑使用OmniXML persistence。
对于XML差异,我已经使用OmniXML编写了一个实用程序,它将执行XML差异,并且有许多XML比较工具。
为了达到这个目的,我使用了OmniXML来完成XML差异化工具,它对我来说非常好。不幸的是,该工具包含许多特定领域的东西,并且是封闭源代码,属于前雇主,因此我无法发布代码。
我比较工具有一个简单的算法:
序列化到一个文本格式(XML,JSON),并做了TDIFF(http://angusj.com/delphi/)会很容易 – mjn
怎么样DFM格式:-)它就像一个JSON前身...从1995年开始。 –