我正在试图找出对一些遗留代码使用依赖注入的最佳方法,这将需要很长时间才能重构并且必须逐步完成.大多数旧类使用"Parent"属性来确定各种事物,而父属性通常通过构造函数参数传递,如下所示:
constructor TParentObject.Create;
begin
FChildObject := TChildObject.Create(Self);
end;
constructor TChildObject.Create(AParent: TParentObject)
begin
FParent := AParent;
end;
Run Code Online (Sandbox Code Playgroud)
这是我们遗留代码库的典型代表.但是,当移动到接口和构造函数注入时,Spring4D框架在创建Child对象时不知道Parent.所以它只会得到一个新的父母而不是现有的父母.当然我可以创建一个属性getter/setter,但这表示该类的"可选"属性,它实际上是一个强制属性.有关更多说明,请参阅以下代码:
unit uInterfaces;
interface
uses
Spring.Collections;
type
IChildObject = interface;
IParentObject = interface
['{8EA8F9A2-E627-4546-8008-0A77DA2B16F1}']
function GetSomethingRequiredByChild: string;
procedure SetSomethingRequiredByChild(const Value: string);
property SomethingRequiredByChild: string read GetSomethingRequiredByChild write SetSomethingRequiredByChild;
function GetChild: IChildObject;
property Child: IChildObject read GetChild;
end;
// This introduces a property getter/setter
// However it also implies that Parent can be NIL which it cannot
IChildObject = interface
['{ECCA09A6-4A52-4BE4-A72E-2801160A9086}']
function GetParent: IParentObject;
procedure …Run Code Online (Sandbox Code Playgroud) 我已经用Delphi编写了一年的代码.但是我对.NET有更多的经验.我正在阅读Nick Hodges的书"编码在Delphi中",他介绍并认可了Spring 4 Delphi框架.
我立即对基于IEnumerable的泛型集合感到兴奋.
然而,我的同事对使用该框架持保留意见.这主要是由于缺乏文档以及Delphi在此继承级别上关于泛型的稳健性/稳定性的一些不安全性.
所以问题.你有什么经历?任何问题?你在生产中使用框架吗?
我们目前仍在XE2上,但预计在未来几个月内转向XE4.
谢谢!
我意识到Delphi不支持接口助手,但在阅读了几个SO主题和Spring4D的来源之后,我想知道有没有办法实现以下目的?源代码评论几乎总结了我正在尝试做的事情,所以这里是:
program IHelper;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Spring,
System.SysUtils;
type
IMyThing = interface
['{01E799A5-9141-4C5E-AA85-B7C9792024D9}']
procedure BasicThing;
end;
TMyThing = class(TInterfacedObject, IMyThing)
strict private
procedure BasicThing;
end;
IMyThingHelper = record
private
FOutage: IMyThing;
public
class operator Implicit(const Value: IMyThing): IMyThingHelper;
procedure HelpfulThing;
end;
TMyThingHelper = class helper for TMyThing
public
class procedure ObjectThing;
end;
{ TOutage }
procedure TMyThing.BasicThing;
begin
Writeln('Basic Thing');
end;
{ IOutageHelper }
procedure IMyThingHelper.HelpfulThing;
begin
Writeln('Helpful thing');
end;
class operator IMyThingHelper.Implicit(const Value: IMyThing): IMyThingHelper;
begin
Result.FOutage …Run Code Online (Sandbox Code Playgroud) 在我看来,IList不能将事件处理程序作为其元素.该程序在PROGRAM退出时具有访问冲突$ C00000005.
如果我使用Delphi RTL的TList,一切都很好.
32位和64位构建都会发生访问冲突.当它发生时,它似乎停在Spring4D的以下几行:
procedure TCollectionBase<T>.Changed(const item: T; action:
TCollectionChangedAction);
begin
if fOnChanged.CanInvoke then
fOnChanged.Invoke(Self, item, action);
end;
Run Code Online (Sandbox Code Playgroud)
以下示例程序可以在Windows上使用RAD Studio Tokyo 10.2.3复制访问冲突.
program Test_Spring_IList_With_Event_Handler;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
Spring.Collections;
type
TSomeEvent = procedure of object;
TMyEventHandlerClass = class
procedure SomeProcedure;
end;
TMyClass = class
private
FEventList: IList<TSomeEvent>;
public
constructor Create;
destructor Destroy; override;
procedure AddEvent(aEvent: TSomeEvent);
end;
procedure TMyEventHandlerClass.SomeProcedure;
begin
// Nothing to do.
end;
constructor TMyClass.Create;
begin
inherited;
FEventList := TCollections.CreateList<TSomeEvent>;
end;
destructor TMyClass.Destroy;
begin
FEventList …Run Code Online (Sandbox Code Playgroud) 可以注册一个具有预期从创建点传递的参数的类吗?
我知道可以这样做:
GlobalContainer.RegisterType<TUserProcessor>.Implements<IUserUpgrader>.
AsTransient.DelegateTo(
function: TUserProcessor
begin
Result := TUserProcessor.Create(GetCurrentUser);
end
);
Run Code Online (Sandbox Code Playgroud)
但是参数被绑定到容器被注册的执行上下文,而不是对象获取的地方.
这样的事情可能就是这样吗?
GlobalContainer.Resolve<IMathService>([FCurrentUser]);
Run Code Online (Sandbox Code Playgroud)
我知道一些peoble的拥护者拥有非常简单的构造函数,但有时候构造函数参数看起来很清楚:
构造的对象需要使用object参数,因此必须满足引用.该参数还使得该约束在类中更加明显.
你可以在方法或属性中分配引用,如果在没有先完成赋值的情况下尝试使用该对象,则可以在每个其他方法中引发和异常.我不喜欢编写这种类型的代码,这只是浪费时间,只是使用构造函数参数并检查那里.代码越少,IMO越好.
此外,对象被传递给使用容器(例如Transaction对象)构造新对象的对象本地,并且具有一些状态(它不是我可以通过容器获得的新对象).
这将是一个难以描述的问题,但是这里有.
我们正在使用Delphi Spring Framework.(http://code.google.com/p/delphi-spring-framework/)
假设我有UnitA声明由ClassA实现的InterfaceA.
类似地,我有UnitB声明由ClassB实现的InterfaceB.
两者都在其各自的初始化部分中使用Spring Container注册了它们的接口和类.
InterfaceA依赖于InterfaceB,但由于我们使用的是Spring,因此UnitA的uses子句中没有UnitB .换句话说,我们已经完成了我们的工作 - 我们已经将UnitA和UnitB分离,但我们仍然可以让InterfaceA依赖于InterfaceB.
但是,鉴于上述情况,我们需要确保UnitA和UnitB都包含在项目中,以便可以解析依赖关系.
想象一下,现在,我们开始一个新项目.该新项目使用UnitA,但开发人员没有意识到如果要使用UnitA,则还必须在项目中包含UnitB.不会出现编译器错误,因为依赖项是在运行时解决的,而不是编译时.
这就是一个问题:在应用程序部署之前,确保对UnitB的这种依赖性是否已知的正确方法是什么?
我们可以预见复杂应用程序中的情况,尽管进行了全面测试,但是可能很长时间没有执行给定的代码路径,并且在部署之前未发现此缺失的依赖关系.
我们已经实现了一个系统,其中每个接口解析调用都伴随着一个Requires调用,在启动时检查并引发异常,确保我们看到错误.但我们想知道是否有"最佳实践"或标准方法来检测此问题或以其他方式处理此问题.
补充: 这是Java和其他语言的问题吗?
我刚刚开始使用Delphi Spring Framework,并想知道当前版本的DI容器是否允许将构造委托给工厂方法而不指定实现类型?
例如类似的东西:
GlobalContainer
.RegisterFactory<ISomeObject>(
function: ISomeObject
begin
Result := CreateComObject(CLASS_SomeObject) as ISomeObject;
end)
.Implements<ISomeObject> // could probably be implied from the above
.AsSingletonPerThread;
Run Code Online (Sandbox Code Playgroud)
如您所见,我的具体用例是COM对象的实例化.在这种情况下,实现我感兴趣的接口的类不是我的应用程序的一部分,但我仍然可以通过调用CreateComObject/ 来创建实例CoCreateInstance.但是,似乎我运气不好,因为Container中的注册似乎总是绑定到实际的实现类.
假设目前不可能这样做,那么你们的专家怎么解决这个问题呢?你会创建一个包装类或虚拟类,或者你只是将COM对象保留在DI容器之外并简单地通过它实例化它们CreateComObject?
我已经下载了最新版本的 Delphi Spring 框架。按照自述文件中的指示,我运行 Build.exe 并选择了两个版本的 Delphi(XE5 和 Seattle)。在 Delphi 安装中,我看不到软件包已安装,也看不到我的库搜索路径已修改。我缺少什么或者我还必须做些什么才能安装和使用它?
在此先感谢您的帮助。
我有一个关于Spring4D框架的TObjectList类的行为的问题.在我的代码创建的几何图形,诸如列表square,circle,triange,各自定义一个单独的类.为了在列表被破坏时自动释放几何图形,我定义了一个类型为TObjectList的列表,如下所示:
procedure TForm1.FormCreate(Sender: TObject);
var
geometricFigures: TObjectList<TGeometricFigure>;
geometricFigure: TGeometricFigure;
begin
ReportMemoryLeaksOnShutdown := true;
geometricFigures := TObjectList<TGeometricFigure>.Create();
try
geometricFigures.Add(TCircle.Create(4,2));
geometricFigures.Add(TCircle.Create(0,4));
geometricFigures.Add(TRectangle.Create(3,10,4));
geometricFigures.Add(TSquare.Create(1,5));
geometricFigures.Add(TTriangle.Create(5,7,4));
geometricFigures.Add(TTriangle.Create(2,6,3));
for geometricFigure in geometricFigures do begin
geometricFigure.ToString();
end;
finally
//geometricFigures.Free(); -> this line is not required (?)
end;
end;
Run Code Online (Sandbox Code Playgroud)
如果我运行此代码,geometricFigures即使我没有Free在列表中调用方法,也会自动从内存中释放列表(注意在finally块中注释掉了行).我期望一个不同的行为,我认为该列表需要显式调用Free(),因为局部变量geometricFigures不使用接口类型.
我进一步注意到,如果列表中的项目没有在for-in循环中迭代(我暂时将其从代码中删除),则列表不会自动释放,并且我会收到内存泄漏.
这引出了以下问题:为什么TObjectList(geometricFigures)类型的列表在迭代其项时会自动释放,但如果从代码中删除for-in循环则不会?
我按照塞巴斯蒂安的建议调试了析构函数.列表项被以下代码破坏:
{$REGION 'TList<T>.TEnumerator'}
constructor TList<T>.TEnumerator.Create(const list: TList<T>);
begin
inherited Create;
fList := list;
fList._AddRef;
fVersion := fList.fVersion;
end;
destructor TList<T>.TEnumerator.Destroy; …Run Code Online (Sandbox Code Playgroud) 考虑这个测试应用:
function RemoveDuplicates(const Input: IEnumerable<Integer>): IEnumerable<Integer>;
begin
// How to implement this function?
end;
var
Enumerable: IEnumerable<Integer>;
UniqueEnumerable: IEnumerable<Integer>;
begin
Enumerable := TCollections.CreateList<Integer>([1, 1, 2, 3, 3, 3, 4]);
UniqueEnumerable := RemoveDuplicates(Enumerable);
UniqueEnumerable.ForEach(
procedure(const I: Integer)
begin
WriteLn(I);
end);
ReadLn;
end.
Run Code Online (Sandbox Code Playgroud)
如何实现该RemoveDuplicates功能(这nub在Haskell中调用)?
delphi ×10
spring4d ×10
delphi-xe2 ×2
com ×1
delphi-xe5 ×1
delphi-xe7 ×1
interface ×1
java ×1
list ×1
unique ×1