我是Delphi的新手,我一直在运行一些测试来查看默认情况下初始化了哪些对象变量和堆栈变量:
TInstanceVariables = class
fBoolean: boolean; // always starts off as false
fInteger: integer; // always starts off as zero
fObject: TObject; // always starts off as nil
end;
Run Code Online (Sandbox Code Playgroud)
这是我习惯使用其他语言的行为,但我想知道在Delphi中依赖它是否安全?例如,我想知道它是否可能依赖于编译器设置,或者可能在不同的机器上以不同的方式工作.依赖于对象的默认初始化值是正常的,还是在构造函数中显式设置所有实例变量?
至于堆栈(过程级)变量,我的测试显示单位化布尔值为真,单位化整数为2129993264,未初始化对象只是无效指针(即不是nil).我猜测规范是在访问它们之前始终设置过程级变量?
我担心这可能是一个虚拟的问题,但它让我非常难过.
我正在寻找将对象的方法传递给过程的最简单方法,以便过程可以调用对象的方法(例如,在超时之后,或者可能在不同的线程中).基本上我想:
我想我可以使用接口实现相同的效果,但我认为还有另一种方法,因为这个"对象过程"类型声明存在.
以下不起作用,但它可能有助于解释我困惑的地方......?
interface
TCallbackMethod = procedure of object;
TCallbackObject = class
procedure CallbackMethodImpl;
procedure SetupCallback;
end;
implementation
procedure CallbackTheCallback(const callbackMethod: TCallbackMethod);
begin
callbackMethod();
end;
procedure TCallbackObject.CallbackMethodImpl;
begin
// Do whatever.
end;
procedure TCallbackObject.SetupCallback;
begin
// following line doesn't compile - it fails with "E2036 Variable required"
CallbackTheCallback(@self.CallbackMethodImpl);
end;
Run Code Online (Sandbox Code Playgroud)
(一旦问题得到解答,我将删除上述代码,除非它以某种方式帮助解释.)
在Delphi中,我希望能够创建一个与类关联的私有对象,并从该类的所有实例中访问它.在Java中,我使用:
public class MyObject {
private static final MySharedObject mySharedObjectInstance = new MySharedObject();
}
Run Code Online (Sandbox Code Playgroud)
或者,如果MySharedObject需要更复杂的初始化,在Java中我可以在静态初始化程序块中实例化并初始化它.
(你可能已经猜到了......我知道我的Java,但我对Delphi很新...)
无论如何,我不希望每次创建MyObject实例时都实例化一个新的MySharedObject,但我确实希望可以从MyObject的每个实例访问一个MySharedObject.(它实际上是日志记录,这促使我试图解决这个问题 - 我正在使用Log4D,我希望将TLogLogger存储为具有日志记录功能的每个类的类变量.)
在Delphi中做这样的事情最好的方法是什么?
我是一位经验丰富的Java程序员,在过去的几年里,他一直在做很多Win32的工作.主要是我一直在使用VB6,但我真的需要转向更好的东西.
我花了一个月左右玩Delphi 2009.我喜欢VCL GUI的东西,Delphi似乎比VB6更适合Windows API调用,我真的很喜欢OO比VB6好多了,我喜欢这个单元IDE附带的测试框架.
但是我真的很难为Delphi没有广泛使用的垃圾收集器这一事实 - 不得不手动释放每个对象或者使用接口来解决所有问题似乎对你以面向对象的方式有效地做事的方式产生了很大的影响.另外,我并不是特别热衷于语法,或者你必须在方法的顶部声明变量.
我可以处理Delphi,但我想知道C++ Builder 2009对我来说是否是更好的选择.我对C++ Builder和C++知之甚少,但我对Delphi知之甚少.我知道C++语言有很多东西,但我怀疑它只需要知道它的一个子集就可以有效地完成工作......我听说今天的C++编程比C++更高效. 10年前.
我将只进行新的开发,所以我不需要掌握C++语言的每个方面 - 如果我能找到每个Java语言功能的等价物,我会很高兴,随着我的进步,我可以开始寻找在更先进的东西更多.(对不起,如果这听起来很痛苦 - 如果是这样,请让我直截了当!)
那么,对于一个对Delphi和C++ Builder都不熟悉的Java程序员来说,你会认为它是Win32 exes和dll高效开发的更好选择,为什么?你认为每个人的利弊是什么?
我正在创建一个包含一些解析字符串日期和时间的方法的库.当字符串参数不可解析时,我很难确定这些方法应该抛出的异常.我正在考虑几种选择:
1. java.lang.IllegalArgumentException - 一个无效的字符串显然是一个非法的论点,但对我来说,IllegalArgumentException通常意味着编程错误,并且很少想要try catch为一个字符串做一个明确的.我认为字符串解析通常用于外部输入,更像是一种值得特殊处理的特殊情况.例如,如果您有一大块代码解析用户输入并对其执行其他操作,您可能希望将该代码包装在try catch块中,以便您可以处理包含无效字符串的用户输入的情况.但是捕获IllegalArgumentException对于查明无效的用户输入并不是很好,因为很可能在代码中有多个地方可以抛出它(而不仅仅是用户输入的解析).
2. java.lang.NumberFormatException - 它Integer.parseInt(String)和其他类似的解析方法一起被抛出java.lang.因此,大多数Java开发人员都熟悉,当您尝试解析可能有效或无效的字符串(例如用户输入)时,它会被捕获.但它的名字中有"数字",所以我不确定它是否真的适合日期和时间这些在某种意义上是数字的东西,但在我看来在概念上是不同的.如果只是它被称为"FormatException"...
3. java.text.ParseException - 不是真正的选择,因为它已被检查.我想要不加控制.
4.自定义异常 -这得到周围人的缺点IllegalArgumentException和NumberFormatException,故能扩大IllegalArgumentException了.但我不认为向库中添加异常是个好主意,除非真的需要它们.引用Josh Bloch的话说,"如果有疑问,请把它留下来".(另外,在我的例子中,对于解析日期和时间的包,很难命名这样的异常:"DateFormatException","TimeFormatException","CalendricalFormatException"(如JSR 310) - 当应用于方法时,似乎没有一个对我来说是理想的解析日期,时间,日期时间等.我认为如果它们都只用于识别不可解析的字符串,那么在单个包中创建多个异常会很愚蠢.)
那么您认为哪种选择最有意义?
注意:我有充分的理由不想使用java.util.Date或Joda Time,或JSR 310,因此无需提出建议.另外我认为如果这个问题保持相当普遍会很好,因为这一定是其他设计API的人一直在努力解决的问题.日期和时间也可以是IP地址,URL或具有需要解析的字符串格式的任何其他类型的信息.
其他图书馆设定的先例
我发现的几个例子:
java.sql.Timestamp.valueOf(String) throws IllegalArgumentException
java.util.Date.parse(String) throws IllegalArgumentException (已弃用的方法,并且未声明异常,但您可以在源代码中看到它)
java.util.UUID.fromString(String) throws IllegalArgumentException
org.apache.axis.types.Time(String) throws NumberFormatException (也是Apache Axis中的Day类)
org.apache.tools.ant.util.DeweyDecimal(String) throws NumberFormatException
com.google.gdata.data.DateTime.parseDateTime(String) throws NumberFormatException
java.lang.Package.isCompatibleWith(String versionString) throws NumberFormatException (在Java 7中,这需要带点的字符串版本号 - 有点像某个意义上的日期或时间)
我确信有很多软件包使用自定义异常,因此我怀疑提供这些例子有很多意义.
在Delphi 2009中,我发现无论何时在应用程序中使用TThread.CurrentThread,我都会在应用程序关闭时收到如下错误消息:
Exception EAccessViolation in module ntdll.dll at 0003DBBA.
Access violation at address 7799DBBA in module 'ntdll.dll'. Write of
address 00000014.
Run Code Online (Sandbox Code Playgroud)
除非它只是我的机器,你可以在几秒钟内复制它:创建一个新的Delphi Forms Application,在表单中添加一个按钮,并使用类似下面的按钮的事件处理程序:
procedure TForm1.Button1Click(Sender: TObject);
begin
TThread.CurrentThread;
end;
Run Code Online (Sandbox Code Playgroud)
在我的Vista的机器和我的XP的机器都我发现,如果我不按一下按钮一切都很好,但如果我做的点击按钮,我得到上面的错误消息,当我关闭应用程序.
所以...我想知道这是不是一个错误,但与此同时我认为我很可能根本不理解你应该如何在Delphi中使用TThreads.我有点像德尔福新手,我很害怕.
使用TThread.CurrentThread有什么明显错误吗?
如果没有,并且你有Delphi 2009,如果你实现我的简单示例项目,你会遇到同样的问题吗?
我正在使用C#来创建一个将广泛分发的.Net类库(DLL).我有一个名为的抽象类Value,我希望它有一个double也称为Valueie 的抽象属性
public abstract class Value {
// Only accessible by subclasses within the project.
internal Value() {}
public abstract double Value {
get;
}
}
Run Code Online (Sandbox Code Playgroud)
但C#编译器不会允许这样-我得到的消息"成员名称不能与它们的封闭类型",作为讨论在这里.
我知道最简单的事情就是更改属性的名称或类的名称......但实际上我希望这些名称是这样的,我很高兴实现一个丑陋的黑客来获取就这样.只要它从使用此DLL的外部代码正常工作即可.
与C#不同,VB.Net 将允许我定义一个与类同名的属性,所以我目前正在研究将我的C#项目与一个VB项目合并,该项目定义了一个Value类(及其Value属性)来制作一个DLL.这似乎并不像我希望的那么简单.
另一种选择是在VB中重写整个项目...不是很吸引人,但如果有必要,我会考虑它.我更喜欢C#而不是VB.Net,但我的首要任务是以我想要的方式获取构建的DLL.
我想知道其他可能的选择.有什么想法可以解决这个问题吗?
编辑:从下面的评论中可以清楚地看到,很多人并不认为课堂上的"价值"这个名字太多了......难道有人会解释为什么这么糟糕吗?我知道它不是很具描述性,但我认为它非常适合我的项目.是因为它是C#中的一个关键字,用于属性设置器吗?
我正在设计一个.NET库,供其他开发人员使用Web和桌面应用程序.我ToString()在各种类中重写,以提供用于调试目的和包含在应用程序日志文件中的信息.
我的一些课程包含数字和日期.
考虑一个包含DateTime被调用date和double被调用的对象value(也可能包含其他字段)...如果我覆盖该对象ToString(),我可能想要做类似的事情:
public override string ToString() {
return "ObjectName[date=" + date + ", value=" + value + "]";
}
Run Code Online (Sandbox Code Playgroud)
但是这将包括来自date.ToString()和的结果value.ToString(),这将给我根据本地化的字符串Thread.CurrentThread.CurrentCulture.
那对我来说,似乎是错的.我的ToString()实现返回的字符串用于调试和日志消息,而不是用户界面.所以我认为返回本地化的字符串只会让事情变得混乱.如果日志文件中出现"2,341",开发人员需要知道线程的值CurrentCulture才能知道它是否意味着2千341或2分341.这对日期更加困惑 - 像xx/xx/xxxx这样的字符串可能是dd/mm/yyyy或mm/dd/yyyy.我不希望我的ToString()方法产生那种歧义.
因此,我倾向于使我的ToString()方法对文化不敏感,以确保所有返回的字符串在不同文化中保持一致.例如,我的ToString()方法在内部就像value.ToString(CultureInfo.InvariantCulture)格式化数字一样.
但是,.NET库中的规范似乎是CurrentCulture在默认的无参数ToString()实现中使用.许多具有ToString()方法的对象也具有ToString(IFormatProvider)方法.就好像.NET的设计者决定默认使用ToString()应该是用户界面显示(本地化),调试和日志(你需要调用它ToString(CultureInfo.InvariantCulture))是次要的.
因此,如果我ToString()以一种对文化不敏感的方式实现我的方法,我觉得我会反对这种方式.但是,当文化敏感性对日志文件或调试没有意义时,默认情况下创建区分文化的字符串似乎很愚蠢.
我可以使用它CurrentCulture来表示我的默认ToString()实现中的数字和日期,并提供ToString(FormatProvider)方法,以便人们可以获得一个文化不敏感的字符串,用于日志文件等.但这似乎是愚蠢的,因为它只是迫使开发人员编写更多的代码来获取我猜他们想要的文化不敏感的字符串(无论他们是否考虑过).
底线是类似的字符串ObjectName[value=12.234, …
我最近买了一台新的Vista PC,但是在使用它的过程中遇到了很多问题,因此我继续在我已经使用多年的慢速XP机器上完成大部分工作(开发和其他).
到目前为止,我已经使用VMware Convertor拍摄了我的旧XP机器的图像,现在我在我的Vista机器上运行它,并且在我的XP虚拟机中完成了我的所有工作.我正在使用VMware Worstation.
所以每天早上我启动我的Vista机器,然后启动我的XP虚拟机,花一整天的时间在XP虚拟机上工作.
是的,您可能会猜到:我与VMware高级用户完全相反......我没有想出快照,链接克隆,或者除了运行VM的绝对基础之外的其他任何东西.但是我把这个系统设置好了,它运行良好.无论如何,一切都比我旧机器上的运行速度快得多.
但是,我担心虚拟机被破坏或者什么东西导致我失去一切.当然我可以支持整个虚拟机,我可以备份虚拟机上的文件,我会,但我想知道使用映射驱动器或公共文件夹或其他东西是否更容易和更安全工作,所以如果XP VM出现问题,我的文件将全部从Vista机器上获得.
这也很好,因为我可以在Vista和XP机器之间轻松共享文件(我确实使用Vista来做奇怪的事情).但我想知道它是否会让我的XP机器上的文件读取和写入速度变慢?(例如,如果我正在编译一个大型Java项目,那将同时涉及大量IO.)
有关如何设置这些内容的信息很容易获得,但我还没有发现如何轻松找出我正在做的最佳方法.大多数人使用VM比我的更先进的目的.
此外,我想知道是否有任何其他提示或重要的考虑因素,这样做的所有你的工作在一体机类型的设置?例如,什么可能出错,我该如何避免呢?还要别的吗?
我正在使用Delphi为Excel制作XLL加载项,这涉及对xlcall32.dll的Excel4v函数进行大量调用.但是,我猜这里的Delphi专家很少使用这个特定的API,我希望在其他API中也可以观察到这个问题.
在C中,特别是在Microsoft Excel 2007 XLL SDK附带的xlcall.h文件中,Excel4v定义为:
int pascal Excel4v(int xlfn, LPXLOPER operRes, int count, LPXLOPER opers[]);
Run Code Online (Sandbox Code Playgroud)
在Delphi我正在使用:
function Excel4v(xlfn: Integer; operRes: LPXLOPER; count: Integer;
opers: array of LPXLOPER): Integer; stdcall; external 'xlcall32.dll';
Run Code Online (Sandbox Code Playgroud)
LPXLOPER是指向结构(在C中)或记录(在Delphi中)的指针.
我一直在做我在Delphi中声明C函数的功课(这篇优秀的文章是一个很好的帮助),我想我正在宣布Excel4v.但是,从Delphi代码调用该函数会导致异常("访问违规......"是我一直看到的),除非后面跟着以下行:
asm pop sink; end;
Run Code Online (Sandbox Code Playgroud)
其中"sink"在某处定义为整数.
我对组装没有任何线索......所以我没想办法用"asm pop sink; end;"来修复异常.但是"asm pop sink; end;" 确实修复了异常.我第一次看到它在这篇有用的文章中用于使用Delphi制作XLL.这是最相关的报价:
"来自Delphi,带有加载项的大绊脚石是堆栈上返回地址之后的额外参数.每次调用Excel都可以免费使用.我从来没有发现它拥有什么,但只要你扔掉它,你的加载项工作正常.添加行asm pop变量,结束;在每次调用之后,变量可以是任何至少4个字节长的全局,局部或对象变量 - 整数就好了.要重复 - 这必须是在每次Excel4v通话后都包括在内.否则你正在制造定时炸弹."
基本上我想了解实际发生了什么,以及为什么.什么可能导致Win32函数返回"堆栈上的返回地址后的额外参数",这实际上是什么意思?
可能有另一种方法来解决这个问题,例如使用不同的编译器选项或声明函数的不同方式?
并且有什么风险可以称为"asm pop sink; end;" 每次调用Excel4v后......?它看起来工作正常,但是,由于我不明白发生了什么,感觉有点危险......
Delphi 2009将GetHashCode函数添加到TObject.GetHashCode返回一个Integer,用于在TDictionary中进行散列.
如果希望对象在TDictionary中正常工作,则需要适当地重写GetHashCode,以便通常不同的对象返回不同的整数哈希码.
但是你对包含双字段的对象做了什么?如何将这些double值转换为GetHashCode的整数?
例如,它通常在Java中完成的方式是使用Double.doubleToLongBits或Float.floatToIntBits之类的方法.后者的文档描述如下:"根据IEEE 754浮点"单格式"位布局返回指定浮点值的表示." 这涉及对浮点值的不同位使用不同掩码的一些按位操作.
在Delphi中有没有这样做的功能?
当您为代码库设计API时,您希望它易于使用,并且难以使用.理想情况下,你希望它是白痴证明.
您可能还希望使其与无法处理泛型的旧系统兼容,例如.Net 1.1和Java 1.4.但是你不希望从较新的代码中使用它会很痛苦.
我想知道以一种类型安全的方式使事物易于迭代的最佳方法......记住你不能使用泛型,因此Java Iterable<T>就是这样的,就像.Net一样IEnumerable<T>.
您希望人们能够在Java中使用增强的for循环,在.Net中(for Item i : items)使用foreach/ For Eachloop,并且您不希望他们必须进行任何转换.基本上,您希望您的API现在既友好又向后兼容.
我能想到的最好的类型安全选项是数组.它们完全向后兼容,并且易于以类型安全的方式进行迭代.但是数组并不理想,因为你不能让它们变成不可变的.因此,当您拥有一个包含数组的不可变对象时,您希望人们能够迭代,为了保持不变性,您必须在每次访问它时提供防御性副本.
在Java中,做得(MyObject[]) myInternalArray.clone();非常快.我确信.Net中的等价物也非常快.如果你喜欢:
class Schedule {
private Appointment[] internalArray;
public Appointment[] appointments() {
return (Appointment[]) internalArray.clone();
}
}
Run Code Online (Sandbox Code Playgroud)
人们可以这样做:
for (Appointment a : schedule.appointments()) {
a.doSomething();
}
Run Code Online (Sandbox Code Playgroud)
它将简单,清晰,类型安全,快速.
但他们可以这样做:
for (int i = 0; i < schedule.appointments().length; i++) {
Appointment a = schedule.appointments()[i];
}
Run Code Online (Sandbox Code Playgroud)
然后它会非常低效,因为整个约会数组将在每次迭代时克隆两次(一次用于长度测试,一次用于获取索引处的对象).如果阵列很小,这不是一个问题,但如果阵列中有数千个项目,则非常可怕.育.
有人会这样做吗?我不确定......我猜这在很大程度上是我的问题.
您可以调用该方法toAppointmentArray()而不是appointments(),这可能会使任何人以错误的方式使用它的可能性降低.但它也会让人们更难以找到他们只想迭代约会的时候.
当然,你会appointments() …