我从单元DBXCommon.pas(在Delphi XE中)获取访问冲突.当我查看代码时,我会看到以下内容(在感叹号处):
function TDBXConnectionFactory.GetConnection(const DBXContext: TDBXContext; const ConnectionProperties: TDBXProperties): TDBXConnection; var ConnectionBuilder: TDBXConnectionBuilder; DelegatePath: TDBXDelegateItem; Connection: TDBXConnection; CombinedProperties: TDBXProperties; begin //... ConnectionBuilder := TDBXConnectionBuilder.Create; Connection := nil; try //..lots of setting ConnectionBuilder properties ConnectionBuilder.FInputPassword := CombinedProperties[TDBXPropertyNames.Password]; Connection := ConnectionBuilder.CreateConnection; Connection.Open; Result := Connection; !! Connection := nil; finally !! Connection.Free; ConnectionBuilder.Free; end; end;
但是我在DBXCommon.pas中看到更像这样的构造(首先分配Nil,然后是Free).这是一些我不知道的构造,或者每次调用这段代码时这是否真的导致访问冲突?
解决方法
在空引用上调用Free始终是安全的.去看看TObject.Free的实现,看看为什么.
此代码是工厂函数的示例.它的工作是创建一个类的新实例,但是如果它失败了,它需要确保它在抛出异常时不会泄漏半创建的实例,因此它调用Free.当它确定它会成功时,它会将结果的所有权转移给调用者.它仍然称为Free,但如果已经转移了所有权,那么它最终会在空引用上调用Free,并且没有任何损害.此代码转移所有权:
Result := Connection; Connection := nil;
我编写工厂函数的方式将取消单独的Connection变量.我直接在Result中构造结果,但如果有异常则释放它,如下所示:
function TDBXConnectionFactory.GetConnection(const DBXContext: TDBXContext; const ConnectionProperties: TDBXProperties): TDBXConnection; var ConnectionBuilder: TDBXConnectionBuilder; DelegatePath: TDBXDelegateItem; Connection: TDBXConnection; CombinedProperties: TDBXProperties; begin //... ConnectionBuilder := TDBXConnectionBuilder.Create; try //..lots of setting ConnectionBuilder properties ConnectionBuilder.FInputPassword := CombinedProperties[TDBXPropertyNames.Password]; Result := ConnectionBuilder.CreateConnection; try Result.Open; except Result.Free; raise; end; finally ConnectionBuilder.Free; end; end;
这具有相同的效果.