这看起来相当简单,也许我只是缺少一些语法粘合...这是我的简单泛型(Delphi XE3)示例:
unit Unit1;
interface
uses
generics.collections;
type
X = class
public
Id: Integer;
end;
XList<T : X> = class( TObjectList<T> )
function Find(Id: Integer) : T;
end;
Y = class(X)
end;
YList = class(XList<Y>)
end;
implementation
{ XList<T> }
function XList<T>.Find(Id: Integer): T;
var
t: X;
begin
for t in Self do
if t.Id = Id then
Result := t;
end;
end.
Run Code Online (Sandbox Code Playgroud)
这不会用"[dcc32错误] Unit1.pas(41)编译:E2010不兼容的类型:'Y'和'X'".这是下线:
YList = class(XList<Y>)
end;
Run Code Online (Sandbox Code Playgroud)
Y来自X所以为什么会出现问题?
我试图通过我们的编译器和带有Windows 8的.NET 4.5来解决问题的根源.我已将其简化为一小段代码,并想知道是否有人对此问题有任何了解.我写了一些C#,它使用反射生成一个显示问题的程序集.C#(在VS2010解决方案中这里https://dl.dropbox.com/u/10931452/sdata.zip)位于本文的底部.它创建了一个类'sdata',并为其添加了一个名为'blank16'的静态字段.然后它创建一个静态构造函数来初始化该字段.生成的可执行文件将写入c:\ temp\sdatatest.exe.当sdatatest在.NET 4.5下运行时,它会生成:
未处理的异常:System.TypeInitializationException:'sdata'的类型初始值设定项引发异常.---> System.AccessViolationException:尝试读取或写入受保护的内存.这通常表明其他内存已损坏.在sdata..cctor()---内部异常堆栈跟踪结束---在sdata.main()
在安装了.NET 4.5的Windows 7上运行时,它会运行.当在早期的.NET框架上运行时,它也会运行 - 并且已经运行了十年.
产生的IL看起来有效:

JITed x86代码看起来也非常有效:

edi的值看起来像加载的可执行文件中的位置而不是托管内存空间中的位置,如果它是只读的,则可以解释访问冲突.为什么这会在Windows 8上发生变化?
C#生成sdatatest程序集:
using System;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
namespace sdata
{
class Program
{
static void Main( string[] args )
{
AssemblyName name = new AssemblyName( );
name.Name = "sdatatest.exe";
string exepath = "c:\\temp\\" + name.Name;
name.CodeBase = "file:://" + exepath;
AssemblyBuilder ass_bldr = Thread.GetDomain( ).DefineDynamicAssembly( name, AssemblyBuilderAccess.RunAndSave, Path.GetDirectoryName( exepath ));
ModuleBuilder module_bldr = ass_bldr.DefineDynamicModule( Path.GetFileName( exepath ), …Run Code Online (Sandbox Code Playgroud) 我在我的应用程序中构建一些动态上下文菜单,代码如下:
mi = new ToolStripMenuItem( caption ) { Tag = c, Enabled = true };
context_menu.Items.Insert( n, mi );
mi.Click += new EventHandler( ContextClick);
Run Code Online (Sandbox Code Playgroud)
这很好用.但是,如果项目数量很大(比如1000),则构建菜单可能需要几分钟.我意识到菜单中的1000个项目是不寻常的,但这里的问题是速度.对于组合框和列表框,有一个BeginUpdate()/ EndUpdate()可以放在这种操作中.菜单有机制吗?
"类似"代码在VB6项目中运行,执行操作所需的时间不到10秒.
我构建了一个玩具电子表格来帮助学习 F#。当我处理新单元格的文本时,我将其存储为可识别类型。为了解析它,我觉得我应该能够做类似的事情:
let cv =
match t with
| _ when t.Length=0 -> Empty
| x when t.[0]='=' -> Expr(x)
| x when t.[0]='\"' -> Str(x)
| (true,i) when Int32.TryParse t -> IntValue(i) // nope!
| _ -> Str(t)
Run Code Online (Sandbox Code Playgroud)
我已经尝试了相当多的组合,但我无法将 TryParse 放在守卫中。我写了一个助手:
let isInt (s:string) =
let mutable m:Int64 = 0L
let (b,m) = Int64.TryParse s
b
Run Code Online (Sandbox Code Playgroud)
我现在可以写:
| _ when Utils.isInt t -> IntValue((int)t)
Run Code Online (Sandbox Code Playgroud)
这似乎是一个糟糕的解决方案,因为它丢弃了转换后的结果。将 TryParse 纳入防护的正确语法是什么?
这让我疯狂.在Visual Studio WinForms设计器中,如果双击一个控件,它将为该控件生成一个XXXX_Load处理程序.这永远不会是你想要的.您希望Click事件或Changed事件或更有可能转到现有的Click事件.你不是一个新的Load事件.更糟糕的是因为偶然发生双击.单击一次,然后再次单击 - bingo一个Load事件处理程序.我使用笔式平板电脑组合,双击非常容易!
有人能告诉我是否有办法阻止这种情况发生.我想要一个Click处理程序.我会安心,没有任何事情发生.
c# ×2
winforms ×2
.net-4.5 ×1
delphi ×1
delphi-xe3 ×1
f# ×1
generics ×1
il ×1
inheritance ×1
menu ×1
performance ×1
windows-8 ×1