要初始化Delphi记录,我总是添加一个初始化为已知良好默认值的方法(类或对象).Delphi还允许使用参数定义记录"构造函数",但是您无法定义自己的无参数"构造函数".
TSomeRecord = record
Value1: double;
Value2: double;
procedure Init;
end;
procedure TSomeRecord.Init;
begin
Value1 := MaxDouble;
Value2 := Pi;
end;
Run Code Online (Sandbox Code Playgroud)
鉴于上述记录,没有警告说记录尚未初始化.开发人员可能会忽略调用Init记录.有没有办法自动将记录初始化为我的默认值,可能不仅仅是一个简单的FillChar;
例如
var
LSomeRecord: TSomeRecord
begin
// someone forgot to call LSomeRecord.Init here
FunctionThatTakesDefaultSomeRecord(LSomeRecord);
end;
Run Code Online (Sandbox Code Playgroud)
如何将记录自动初始化为我的默认值?
[注意]我不想在答案后修改问题.任何读者都可以阅读关于使用类方法进行初始化而不是变异对象方法的最佳实践的注释.
德尔福柏林10.1增加了[弱]参考.Marco Cantu的博客有一些基础知识.
对于我的测试,我创建了两个包含两个自动化对象类型的COM库.容器对象包含内容对象的列表,而内容对象包含对其容器的弱引用.
以下两个方案已经过测试并正常工作(弱引用设置为null并释放内存):
但是,当我将coclasses放在两个单独的库中时,代码会生成"无效类类型转换",删除[weak]属性时错误消失.请原谅奇数样本,其目的只是为了使问题最小化,不应该作为标准编码实践
这是第一个库.ridl文件,它定义了接口和容器的CoClass:
[
uuid(E1EE3651-A400-49BF-B5C5-006D9943B9C0),
version(1.0)
]
library DelphiIntfComLib
{
importlib("stdole2.tlb");
interface IMyContainer;
interface IMyContent;
coclass MyContainer;
[
uuid(A7EF86F7-40CD-41EE-9DA1-4D9B7B24F06B),
helpstring("Dispatch interface for MyContainer Object"),
dual,
oleautomation
]
interface IMyContainer: IDispatch
{
[id(0x000000C9)]
HRESULT _stdcall Add([in] IMyContent* AMyContent);
};
[
uuid(BFD6D976-8CEF-4264-B95A-B5DA7817F6B3),
helpstring("Dispatch interface for MyContent Object"),
dual,
oleautomation
]
interface IMyContent: IDispatch
{
[id(0x000000C9)]
HRESULT _stdcall SetWeakReferenceToContainer([in] IMyContainer* AContainer);
};
[
uuid(1F56198B-B1BE-4E11-BC78-0E6FF8E55214)
]
coclass MyContainer
{
[default] interface IMyContainer;
};
};
Run Code Online (Sandbox Code Playgroud)
这是我的容器实现
unit Unit1; …Run Code Online (Sandbox Code Playgroud) 当使用TADOQuerywith [eoAsyncFetchNonBlocking]和附加到OnFetchComplete事件时,我发现它OnFetchComplete没有在主线程中执行(在XE4和XE8中测试).我认为这是一个错误*,因为我们大多数人都会在这些类型的事件中在UI中工作.我认为这是大型项目中一些问题的根源,我需要一个解决方法.
[编辑]*在阅读ADO文档后,我知道承认这可能不是一个错误,但多线程问题仍然存在.
是否有一种优雅的方法来强制在此处理程序中使用代码在主线程上执行?我不想使用计时器(但如果这是我将采取的唯一解决方案).或者,是否存在ADO同步对象,我可以在此等待或向ADO提供商发送其他形式的信令?
这是一个简化的示例,显示了问题.我的项目更复杂,工厂创建和填充这些数据集,但这里类似于将数据集附加到网格内部ADOQuery1FetchComplete.
unit Unit4;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.DB, Data.Win.ADODB, Vcl.StdCtrls;
type
TForm4 = class(TForm)
Button1: TButton;
Button2: TButton;
ADOQuery1: TADOQuery;
ADOConnection1: TADOConnection;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure ADOQuery1FetchComplete(DataSet: TCustomADODataSet;
const Error: Error; var EventStatus: TEventStatus);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
FMainThreadID : DWORD;
public
{ Public declarations }
end;
var
Form4: TForm4;
implementation
{$R *.dfm} …Run Code Online (Sandbox Code Playgroud) 我可以将内存从缓冲区复制到安全数组中,如下所示
function GetVarArrayFromBuffer(ABuffer : pByte; ASizeInBytes: Cardinal) : OleVariant;
var
LVarArrayPtr: Pointer;
begin
Result := VarArrayCreate([0, ASizeInBytes - 1], varByte);
LVarArrayPtr := VarArrayLock(Result);
try
Move(ABuffer^, LVarArrayPtr^, ASizeInBytes);
finally
VarArrayUnLock(Result);
end;
end;
Run Code Online (Sandbox Code Playgroud)
但是,有没有办法直接将我的指针和大小传递到一个varArray类型OleVariant而不复制内存?
[编辑]
我可以看到里面的数组OleVariant是a SAFEARRAY(定义为PVarArray = ^TVarArray),所以看起来应该有一种方法可以通过填充a中的值TVarArray并设置VType和中的VArray值来实现OleVariant.
我在测试项目中使用RTTI来评估枚举值,最常见的是对象的属性.如果枚举超出范围,我想显示类似于评估/修改IDE窗口所显示的文本.像"(超出范围)255"之类的东西.
下面的示例代码使用TypeInfo将枚举之外的值显示为使用时的访问冲突GetEnumName.使用RTTI或TypeInfo的任何解决方案都会对我有帮助,我只是不知道我的测试代码中的枚举类型
program Project60;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, TypInfo;
Type
TestEnum = (TestEnumA, TestEnumB, TestEnumC);
const
TestEnumUndefined = TestEnum(-1);
procedure WriteEnum(const ATypeInfo: PTypeInfo; const AOrdinal: Integer);
begin
WriteLn(Format('Ordinal: %d = "%s"', [AOrdinal, GetEnumName(ATypeInfo, AOrdinal)]));
end;
var
TestEnumTypeInfo: PTypeInfo;
begin
try
TestEnumTypeInfo := TypeInfo(TestEnum);
WriteEnum(TestEnumTypeInfo, Ord(TestEnumA));
WriteEnum(TestEnumTypeInfo, Ord(TestEnumB));
WriteEnum(TestEnumTypeInfo, Ord(TestEnumC));
WriteEnum(TestEnumTypeInfo, Ord(TestEnumUndefined)); //AV
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
ReadLn;
end.
Run Code Online (Sandbox Code Playgroud) delphi ×5
delphi-xe4 ×2
asynchronous ×1
com ×1
delphi-xe8 ×1
precision ×1
processor ×1
rtti ×1
safearray ×1
tadoquery ×1