针对带有 TStrings 和 TStringList 的接口进行编码
我饶有兴趣地阅读了 Nick Hodges 博客 为什么你应该使用接口 由于我已经爱上了编码中更高级别的接口,因此我决定研究如何将其扩展到相当低的级别,并研究 VCL 类中对此存在哪些支持。
我需要的一个常见构造是使用 TStringList 做一些简单的事情,例如这段代码将一个小文本文件列表加载到逗号文本字符串中:
var
MyList : TStrings;
sCommaText : string;
begin
MyList := TStringList.Create;
try
MyList.LoadFromFile( 'c:\temp\somefile.txt' );
sCommaText := MyList.CommaText;
// ... do something with sCommaText.....
finally
MyList.Free;
end;
end;
如果我可以使用 MyList 作为接口进行编写,这似乎是一个很好的简化 - 它将摆脱 try-finally 并提高可读性:
var
MyList : IStrings;
//^^^^^^^
sCommaText : string;
begin
MyList := TStringList.Create;
MyList.LoadFromFile( 'c:\temp\somefile.txt' );
sCommaText := MyList.CommaText;
// ... do something with sCommaText.....
end;
虽然我看不到定义的 IStrings - 当然不在 Classes.pas 中,尽管有与在线 OLE 编程相关的引用。它存在吗?这是有效的简化吗?我使用的是德尔福XE2。
I read with interest Nick Hodges blog on Why You Should Be Using Interfaces
and since I'm already in love with interfaces at a higher level in my coding I decided to look at how I could extend this to quite low levels and to investigate what support for this existed in the VCL classes.
A common construct that I need is to do something simple with a TStringList, for example this code to load a small text file list into a comma text string:
var
MyList : TStrings;
sCommaText : string;
begin
MyList := TStringList.Create;
try
MyList.LoadFromFile( 'c:\temp\somefile.txt' );
sCommaText := MyList.CommaText;
// ... do something with sCommaText.....
finally
MyList.Free;
end;
end;
It would seem a nice simplification if I could write with using MyList as an interface - it would get rid of the try-finally and improve readability:
var
MyList : IStrings;
//^^^^^^^
sCommaText : string;
begin
MyList := TStringList.Create;
MyList.LoadFromFile( 'c:\temp\somefile.txt' );
sCommaText := MyList.CommaText;
// ... do something with sCommaText.....
end;
I can't see an IStrings defined though - certainly not in Classes.pas, although there are references to it in connection with OLE programming online. Does it exist? Is this a valid simplification? I'm using Delphi XE2.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
RTL/VCL 中没有接口可以执行您想要的操作(公开与 TStrings 相同的接口)。如果你想使用这样的东西,你需要自己发明它。
您可以使用如下包装器来实现它:
当然,您可以将
TStrings
接口的其余部分包装在一个真正的类中。使用像这样的包装类来执行此操作,以便您只需访问它的实例即可包装任何类型的TStrings
。像这样使用它:
您可能更喜欢添加一个辅助函数来实际执行调用
TIStrings.Create
的肮脏工作。另请注意,寿命可能是一个问题。您可能需要此包装器的变体,该变体不会接管底层
TStrings
实例的生命周期管理。这可以通过 TIStrings 构造函数参数进行安排。我个人认为这是一个有趣的思想实验,但并不是一个真正明智的方法。
TStrings
类是一个抽象类,它几乎具有接口提供的所有优点。我认为按原样使用它没有真正的缺点。There is no interface in the RTL/VCL that does what you want (expose the same interface as
TStrings
). If you wanted to use such a thing you would need to invent it yourself.You would implement it with a wrapper like this:
Naturally you would wrap up the rest of the
TStrings
interface in a real class. Do it with a wrapper class like this so that you can wrap any type ofTStrings
just by having access to an instance of it.Use it like this:
You may prefer to add a helper function to actually do the dirty work of calling
TIStrings.Create
.Note also that lifetime could be an issue. You may want a variant of this wrapper that does not take over management of the lifetime of the underlying
TStrings
instance. That could be arranged with aTIStrings
constructor parameter.Myself, I think this to be an interesting thought experiment but not really a sensible approach to take. The
TStrings
class is an abstract class which has pretty much all the benefits that interfaces offer. I see no real downsides to using it as is.由于 TStrings 是一个抽象类,因此它的接口版本不会提供太多内容。无论如何,该接口的任何实现者肯定都是
TStrings
后代,因为没有人愿意重新实现TStrings
所做的所有事情。我认为需要TStrings
接口有两个原因:自动资源清理。为此,您不需要特定于
TStrings
的接口。相反,请使用 JCL 中的ISafeGuard
界面。这是一个例子:<前><代码>变量
G:ISafeGuard;
我的列表:TStrings;
sCommaText:字符串;
开始
MyList := TStrings(Guard(TStringList.Create, G));
MyList.LoadFromFile('c:\temp\somefile.txt');
sCommaText := MyList.CommaText;
// ...用 sCommaText 做一些事情......
结尾;
要保护应具有相同生命周期的多个对象,请使用
IMultiSafeGuard
。与外部模块的互操作。这就是
IStrings
的用途。 Delphi 使用TStringsAdapter
类来实现它,当您在现有TStrings
后代上调用GetOleStrings
时,会返回该类。当您有字符串列表并且需要授予对需要IStrings
或IEnumString
接口的另一个模块的访问权限时,请使用它。否则,这些接口使用起来很笨拙——它们都不提供TStrings
所做的所有事情——所以除非必要,否则不要使用它们。如果您正在使用的外部模块保证将始终使用与您的模块编译时相同的Delphi版本进行编译,那么您应该使用运行时包并且直接传递
TStrings
后代。共享包允许两个模块使用相同的类定义,并且内存管理大大简化。Since
TStrings
is an abstract class, an interface version of it wouldn't provide much. Any implementer of that interface would surely be aTStrings
descendant anyway, because nobody would want to re-implement all the thingsTStrings
does. I see two reasons for wanting aTStrings
interface:Automatic resource cleanup. You don't need a
TStrings
-specific interface for that. Instead, use theISafeGuard
interface from the JCL. Here's an example:To protect multiple objects that should have the same lifetime, use
IMultiSafeGuard
.Interoperation with external modules. This is what
IStrings
is for. Delphi implements it with theTStringsAdapter
class, which is returned when you callGetOleStrings
on an existingTStrings
descendant. Use that when you have a string list and you need to grant access to another module that expectsIStrings
orIEnumString
interfaces. Those interfaces are clunky to use otherwise — neither provides all the thingsTStrings
does — so don't use them unless you have to.If the external module you're working with is something that you can guarantee will always be compiled with the same Delphi version that your module is compiled with, then you should use run-time packages and pass
TStrings
descendants directly. The shared package allows both modules to use the same definition of the class, and memory management is greatly simplified.