分享
 
 
 

Delphi for .Net 编译器预览 - by John Kaster

王朝delphi·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

Welcome zhang jinyu

www.borland.com

AppServer

C++

CORBA

Delphi & Kylix

InterBase

Java

Linux

TeamSource DSP

Borland Developer Network Home >Delphi & Kylix> Platforms

Delphi for .NET compiler preview - by John Kaster

Abstract:A first look at the Delphi for .NET compiler features and Delphi's new language syntax

by John Kaster and Danny Thorpe

At BorCon 2002, Borland started providing more technical details on our support under development for the .NET platform. This article introduces some of the planned enhancements to the Delphi language and introduces the prototype "Delphi for .NET" compiler. Unless otherwise indicated, the language features discussed here will first be seen in the Delphi for .NET compiler. Furthermore, all of the features discussed in this article may not be introduced in the preview release. When possible, features already implemented in the compiler will be listed, but since the compiler is in beta right now, not much emphasis will be placed on distinguishing what's currently implemented and what's not.

For a good, brief overview of .NET and an introduction to some of the terms mentioned in this article, see http://arstechnica.com/paedia/n/net/net-1.html.

DCCIL

The Delphi for .NET compiler produces Common Intermediate Language (CIL) applications. These applications can run anywhere the .NET run-time is available as fully managed applications. This means that Delphi applications can now move beyond their traditional Windows/Intel platform to any other platform that has a .NET runtime, such as the .NET compact framework available for tablet PCs, phones, and PDAs.

The Delphi command line compiler for IL is dccil.exe. Here's what currently shows up when you run it without any parameters. (This output is guaranteed to change before we release the Delphi for .NET preview with Delphi 7.)

Borland Delphi Version 16.0

Copyright (c) 1983,2002 Borland Software Corporation

Confidential pre-release version built Aug 2 2002 17:29:33

Syntax: dccil [options] filename [options]

-A<unit>=<alias> = Set unit alias -LU<package> = Use package

-B = Build all units -M = Make modified units

-CC = Console target -N<path> = DCU output directory

-CG = GUI target -O<paths> = Object directories

-D<syms> = Define conditionals -P = look for 8.3 file names also

-E<path> = EXE output directory -Q = Quiet compile

-F<offset> = Find error -R<paths> = Resource directories

-GD = Detailed map file -U<paths> = Unit directories

-GP = Map file with publics -V = Debug information in EXE

-GS = Map file with segments -VR = Generate remote debug (RSM)

-H = Output hint messages -W = Output warning messages

-I<paths> = Include directories -Z = Output 'never build' DCPs

-J = Generate .obj file -$<dir> = Compiler directive

-JP = Generate C++ .obj file --help = Show this help screen

-K<addr> = Set image base addr --version = Show name and version

Compiler switches: -$<letter><state> (defaults are shown below)

A8 Aligned record fields P+ Open string params

B- Full boolean Evaluation Q- Integer overflow checking

C+ Evaluate assertions at runtime R- Range checking

D+ Debug information T- Typed @ operator

G+ Use imported data references U- Pentium(tm)-safe divide

H+ Use long strings by default V+ Strict var-strings

I+ I/O checking W- Generate stack frames

J- Writeable structured consts X+ Extended syntax

L+ Local debug symbols Y+ Symbol reference info

M- Runtime type info Z1 Minimum size of enum types

O+ Optimization

product version: VER160

debug level: 2

In an effort to maintain the trend of asking about pronunciations ("Is it 'delf-ee' or 'delf-eye'?"), I feel obligated to mention that the R&D team pronounces the compiler as "diesel."

A Delphi for .NET GUI application

As with Kylix, a basic step in our .NET support was getting a compiler that actually produces the appropriate "machine code" executable. In this case, that machine is .NET. A form designer is not currently available for Delphi for .NET, so you will notice that the following code actually initializes the menu items, button, listbox, and up/down control.

program ConvertIt;

uses

System.Drawing,

Borland.Delphi.SysUtils, Borland.Delphi.Conversions, Borland.Vcl.Controls;

type

TForm1 = class(TForm)

private

DoitButton: TButton;

CelsiusEdit: TSpinEdit;

ResultList: TListBox;

MainMenu: TMainMenu;

FileItem: TMenuItem;

ExitItem: TMenuItem;

HelpItem: TMenuItem;

AboutItem: TMenuItem;

procedure DoitButtonClick(Sender: TObject; Args: TEventArgs);

procedure ExitItemClick(Sender: TObject; Args: TEventArgs);

procedure AboutItemClick(Sender: TObject; Args: TEventArgs);

protected

function DecimalToFloat(const AValue: Decimal): Double;

function FloatToDecimal(const AValue: Double): Decimal;

procedure ReadState;

public

constructor Create;

procedure Convert;

end;

var

Form1: TForm1;

function TForm1.DecimalToFloat(const AValue: Decimal): Double;

begin

Result := System.Convert.ToDouble(AValue);

end;

function TForm1.FloatToDecimal(const AValue: Double): Decimal;

begin

Result := System.Convert.ToDecimal(AValue);

end;

procedure TForm1.Convert;

var

LCelsius: Double;

function NthDegree(const Scale: string; const Temperature: double): string;

begin

Result := Format('%s = %8.2f', [Scale, Temperature]);

end;

begin

LCelsius := DecimalToFloat(CelsiusEdit.Value);

with ResultList.Items do

begin

Clear;

Add(NthDegree('Celsius', LCelsius));

Add(NthDegree('Fahrenheit', CelsiusToFahrenheit(LCelsius)));

Add(NthDegree('Kelvin', CelsiusToKelvin(LCelsius)));

Add(NthDegree('Rankine', CelsiusToRankine(LCelsius)));

Add(NthDegree('Reaumur', CelsiusToReaumur(LCelsius)));

end;

end;

procedure TForm1.DoitButtonClick(Sender: TObject; Args: TEventArgs);

begin

Convert;

end;

procedure TForm1.ExitItemClick(Sender: TObject; Args: TEventArgs);

begin

Close;

end;

procedure TForm1.AboutItemClick(Sender: TObject; Args: TEventArgs);

begin

TMessageBox.Show(Text + ' whatever');

end;

constructor TForm1.Create;

begin

inherited Create;

ReadState;

end;

procedure TForm1.ReadState;

begin

MainMenu := TMainMenu.Create;

FileItem := TMenuItem.Create;

ExitItem := TMenuItem.Create;

HelpItem := TMenuItem.Create;

AboutItem := TMenuItem.Create;

MainMenu.MenuItems.Add(FileItem);

MainMenu.MenuItems.Add(HelpItem);

FileItem.MenuItems.Add(ExitItem);

FileItem.Text := 'File';

ExitItem.Text := 'Exit';

ExitItem.add_Click(ExitItemClick);

HelpItem.MenuItems.Add(AboutItem);

HelpItem.Text := 'Help';

AboutItem.Text := 'About...';

AboutItem.add_Click(AboutItemClick);

DoitButton := TButton.Create;

with DoitButton do

begin

Left := 8;

Top := 8;

Width := 33;

Height := 25;

Text := 'Go';

add_Click(DoitButtonClick);

end;

CelsiusEdit := TSpinEdit.Create;

with CelsiusEdit do

begin

Left := 48;

Top := 8;

Width := 177;

Value := FloatToDecimal(100);

Maximum := FloatToDecimal(10000);

Minimum := FloatToDecimal(-1000);

add_ValueChanged(DoitButtonClick);

end;

ResultList := TListBox.Create;

with ResultList do

begin

Left := 8;

Top := 40;

Width := 217;

Height := 217;

end;

ClientSize := System.Drawing.Size.Create(240, 270);

Menu := MainMenu;

Controls.Add(DoitButton);

Controls.Add(CelsiusEdit);

Controls.Add(ResultList);

Text := 'ConvertIt!';

ControlBox := True;

MinimizeBox := True;

Convert;

end;

begin

Form1 := TForm1.Create;

TApplication.Run(Form1);

end.

Note! The unit Borland.Delphi.Conversions contains the various Celsius temperature conversion routines. The unit Borland.VCL.Controls is a preliminary version that will not be included with the initial preview release.

The source code listed above is contained in ConvertIt.dpr, and is sure to change even before we ship the .NET preview compiler with Delphi 7. If we compile it, we'll see:

[d:d4.netconvert.net]dccil ConvertIt.dpr

Borland Delphi Version 16.0

Copyright (c) 1983,2002 Borland Software Corporation

Confidential pre-release version built Aug 2 2002 17:29:33

Borland.Delphi.Conversions.pas(60)

Borland.Vcl.Controls.pas(38)

ConvertIt.dpr(159)

260 lines, 0.64 seconds, 12232 bytes code, 0 bytes data.

After compiling the application, of course we should run it. Here's what the application looks like after a little resizing to minimize the image size.

Fully Managed Code

This application is a 100% managed code application, as the results of PEVerify show:

[d:d4.netconvert.net]peverify ConvertIt.exe

Microsoft (R) .NET Framework PE Verifier Version 1.0.3705.0

Copyright (C) Microsoft Corporation 1998-2001. All rights reserved.

All Classes and Methods in ConvertIt.exe Verified

You can use Microsoft IL Disassembler (ildasm) to examine the executable.

ILDasm running on ConvertIt.exe

You can examine the .NET assembler code for any module.

.NET assembler code for function NthDegree

Delphi for .NET code also works with Lutz Roeder's excellent utility, Reflector. (This link contains some other great .NET utilities as well.)

ConvertIt examined in Reflector

The .NET compiler

The Delphi for .NET compiler is more than just a port of the existing Delphi compiler. There is a new code generator, a new linker, significant new syntax, and a new runtime library. Of course, it is also very important to maintain language compatibility, so you will see some familiar old friends in Delphi for .NET as well:

Strings & Arrays

Records

Classes

Interfaces

Properties & Events

Sets

Text files

Local Procedures

Variants

Components

Streams

New, Dispose

Readln, Writeln

Format

Component Streaming

Random

In order to fully embrace the CLR and make Delphi a first class citizen in the new world of managed code, some language features must be deprecated, and others are the subject of ongoing research. Though many of these details are still being researched and implemented, it is hoped that the following information will be useful for understanding the new language features of Delphi for .NET.

Unsafe code warnings in Delphi

Starting with Delphi 7, the compiler includes three new warnings that can help you locate code that is non-portable (i.e. it uses a deprecated language feature or type), or unsafe in the .NET Framework. In the .NET Framework, "unsafe" simply means that the code cannot be verified by the static analysis performed by the CLR when the code is loaded. The compiler can warn about the usage of unsafe types, unsafe code, and unsafe casts.

Unsafe types

PChar, PWideChar, and PAnsiChar

Untyped pointers

Untyped var and out parameters

File of <type>

Real48

Variant records (records containing overlapping fields)

Unsafe code

Absolute variables

Addr(), Ptr(), Hi(), Lo(), Swap() standard procedures

BlockRead(), and BlockWrite()

Fail()

GetMem(), FreeMem(), ReallocMem()

inline assembler

the @ operator

Unsafe casts

Casting an object instance to a type that is not an ancestor or descendent of the instance type

Casting a record type to anything else

These new warnings are disabled by default. They can be enabled with the IDE Project Options dialog box, or with the compiler directive:

{$WARN UNSAFE_CODE ON}

They can also be enabled with the -W command line switch:

dcc32 -W+UNSAFE_CODE

Note there is no space before or after the '+' character on the command line switch.

Note: These new warnings are in the Delphi 7 (and beyond) compiler for Win32 (dcc32). They are not in the Delphi for .NET Preview compiler (dccil).

Deprecated Language Features

The dccil compiler will also deprecate some existing language features, listed in the following table.

Keyword/Language Feature

Notes

Real48 six byte floating type

GetMem(), FreeMem(), and ReallocMem()

Use dynamic arrays, or rely on automatic dispose pattern implementation

BlockRead(), BlockWrite()

Absolute directive, Addr, and @

Pre-Delphi object syntax (type foo = object)

TVarData, Variant internals

Variant semantics will be supported but not as TVarData

File of <type>

This construct cannot be implemented because the Delphi compiler cannot know the size of <type> on the target platform (e.g. a handheld device). The JIT compiler for the specific platform determines the size of intrinsic types.

Untyped var and out parameters

Untyped const parameters are still supported

PChar

In a future release Delphi for .NET will support unsafe managed code (i.e. pointers). Unsafe, unmanaged pointers are not supported in the preview release.

automated and dispid directives

Inline assembly - asm statement

TInterfacedObject

AddRef, QueryInterface, and Release are deprecated. In the preview release TInterfacedObject is an alias for TObject.

Dynamic aggregation

Dynamic aggregation of interfaces is not supported by the CLR, because it cannot be statically verified. In Delphi for .NET, all interfaces must be declared on the type. Dynamic aggregation is provided by the implements keyword, as the following code illustrates.

program Project1;

type

i = interface

procedure Wombat;

end;

TA = class(TInterfacedObject, i)

procedure Wombat;

end;

TC = class(TInterfacedObject, i)

fa: TA;

property a: TA read fa implements i;

end;

{ TA }

procedure TA.Wombat;

begin

end;

begin

end.

ExitProc

CLR and Delphi

The new Delphi compiler will provide access to the .NET CLR (Common Language Run-time). Delphi developers will be instantly familiar with the CLR not just because it resembles the VCL so closely, but also because compatibility type mappings will be provided.

The following table shows some classes and technology areas that map easily between Delphi and the .NET runtime.

Delphi for .NET

.NET CLR

TObject

System.Object

String

System.String

Variant

System.ValueType

Records

System.ValueType

Exception

System.Exception

TComponent

System.ComponentModel.Component

Database connectivity

ADO.NET (and DataSnap direct drivers)

RIO Web Services

On top of System.Web.Services

GUI

System.Windows.Forms plus VCL

Assemblies and Delphi

The Delphi for .NET compiler treats CLR assemblies like Delphi packages. The compiler supports direct symbol importing from metadata. Header file translations are no longer needed. Symbols can be imported from any Common Language Specification (CLS) compliant .NET assembly, produced by any .NET language tool. Conceptually, every .NET assembly contains the equivalent of a DCP (which is a collection of DCUs) and a BPL, all lumped into one file.

The compiler supports the -lu<name> switch to specify which assemblies to link with or allow access to. These assemblies do not have to be Delphi assemblies. Any CLR assembly can be used directly with Delphi for .NET, with no translations or conversions. Just as you use -lu for Delphi packages, you can use -lu for any CLR assembly.

The Delphi package syntax produces assemblies. Furthermore, the package syntax will still provide the option of linking referred code directly into your exe, or making it an external reference.

The .NET assemblies don't give you the option of internal or external linking of code. You can support internal or external linking by distributing the DCUs as well as DCPs + BPLs. You cannot link code compiled in a package into an exe. You have to have a DCU (or source) to do that. The DCCIL compiler behaves the same as the DCC32 compiler.

You should also know that Delphi for .NET will preserve the case for the namespaces you create. C#'s recognition of namespaces is case sensitive, so if you use a Delphi for .NET assembly with C#, you will need to match the original case of the namespace you created. Delphi's recognition of namespaces is not case sensitive, so if you don't keep this behavioral difference of the languages in mind, you might run into problems later.

Delphi Language Enhancements

I'm sure you were all looking closely at the code above, even though I told you it would change. Some of the enhancements to Delphi are obvious by looking at the source code, but not all of them are demonstrated in the above code sample.

Let's look at a partial list of Delphi language enhancements.

Unit namespaces

By examining the above source code, one obvious change should be the support for unit namespaces. Namespaces allow you to access units with fully qualified identifiers, such as:

uses Borland.Delphi.SysUtils;

The Delphi unit defines its own namespace with dotted names in the unit identifiers and file names. (The file name and unit name still match, with the ".pas" omitted from the unit name.)

Project namespace

You can configure project-specific namespace resolution. Project namespaces are a great way to eliminate uses clause IFDEFs. The project namespace will determine how the unit name references are fully resolved.

Project namespace search path

There will also be support for a project namespace search path, which supports searching the namespace path for unqualified unit names on the search path. Consider this hypothetical example:

uses Forms;

This reference would resolve to Borland.VCL.Forms for a VCL project, and Borland.CLX.Forms for a CLX project. Clearly, this will make code for cross-platform development (such as .NET, Win32, and Linux) much easier to write and maintain.

Default project namespace

You can also create units that can be compiled into multiple project namespaces. For example,

unit MyControl;

would compile to Borland.VCL.MyControl.dcuil for a VCL project, and Borland.CLX.MyControl.dcuil for a CLX project.

Qualified identifiers

Reserved words or keywords are allowed after the first identifier. For example, in the following code:

var

foo : System.Label;

Qualified identifiers can appear in type expressions, but not in identifier declarations. System.Label would be allowed as a valid type expression although label is a reserved word in Delphi. Future compiler plans for the extended identifier syntax include allowing the use of Unicode/UTF8 identifiers after the first "standard" identifier.

The Common Language Specification includes this extended identifier syntax. The dccil compiler will provide access to all CLS compliant symbols in CLR assemblies.

Nested types

Consider the following code:

type

TMyClass = class

Fdata: Integer;

const foo = 12;

type TNestedClass = class

procedure Hello;

end;

procedure Green;

end;

...

var

MyClass : TMyClass;

MyNest: TMyClass.TNestedClass;

...

begin

MyClass.Fdata := 15;

MyNest.TNestedClass := TMyClass.TNestedClass.Create;

MyNest.Hello;

MyClass.Green;

end;

The TNestedClass type is nested inside of the TMyClass type, but doesn't affect instances of TMyClass because data fields defined in TMyClass.TNestedClass do not occupy space in instances of TMyClass. Nested types are an extension of the namespace idea; logical containment by naming convention, with no physical manifestation.

In the above example, MyNest is not freed because it will be garbage-collected by the .NET runtime.

Custom Attributes

Delphi for .NET will support standard attributes, such as Conditional, Obsolete, Serializable, and web methods. You will also be able to create custom attributes, such as those displayed here:

type

[ FooAttribute('Hello', 23) ]

TMyClass = class

[ SpecialDataAttribute ]

Fdata: Integer;

[ WebMethod, DebuggerStepThrough ]

function SampleCount: Byte;

end;

Declaring custom attributes

Delphi allows you to create custom attributes you can use for any of your .NET application source code, such as the TQuantumAttribute declared here:

type

TQuantumAttribute = class(TCustomAttribute)

constructor Create;

constructor Create(Name: String);

property Name: String ...;

property Spin: Double ...;

property Color: TQuarkColor ...;

end;

A poster child for custom attributes might be the DLLImportAttribute. The Borland.Win32.Windows unit will be using that attribute for indicating the requirement for Windows run-time DLLs. CLR supports more options for referencing external DLL functions than regular old PE DLL Imports. Rather than add more special syntax to the language to cover those additional CLR-specific options, the additional info can be carried in an attribute. The compiler can remain blissfully ignorant of the payload for all but a handful of custom attributes.

Class (static) data

You can have class variables in your objects. This allows you to do things like perform instance counts or track information that is class specific rather than instance specific in your objects.

type

TMyClass = class

class Fdata: Integer;

class property Foo: String ...;

class procedure One;

class static procedure Two;

end;

Class properties

Class properties work like class fields. The getters and setters must be class methods or class fields.

Class static methods

Class static methods work the same as traditional Delphi class methods, except that there is no "self" parameter available in the method body. This is a CLR requirement because some languages do not support the hybrid behaviors Delphi has, where you can have routines that are not part of an object. Traditional Delphi class methods (which do have a "Self" in the body of the method) will also be supported.

Value types

Types can be "boxed" into object wrappers. These value types are not reference types. They are the actual instance of the type. Value semantics are supported for assignment and copying data. Record types are an example of value types in Delphi. Records can inherit from other records, and records can contain non-virtual methods, properties, and nested types.

When value types are boxed, a fresh copy of the value is made and a distinct object reference is returned. This distinct object reference is a reference to data that is completely independent of the underlying value type. For the following code,

TObject(12).ToString

the code TObject(12) boxes an integer into an object.

Boxing of value types in Delphi for .NET is a requirement. Boxing support is not planned for Win32 or Linux Delphi language implementations.

Records with inheritance

Delphi records will be implemented as value types in CLR. Record inheritance is an aspect of value types. Records with non-virtual methods is another aspect of value type support.

Records with methods

The declaration of methods on TRecord is supported. These behave as static non-virtual methods.

Sealed classes

A sealed class cannot be inherited from. Value types can only inherit from abstract value type classes, and only sealed value type classes can be instantiated. Value types are highly deterministic, and decidedly non-polymorphic.

Final methods

The final directive on a virtual method (or override) indicates that this method cannot be overridden in descendent classes. Descendents may still introduce new virtual methods with the same name as the inherited method, but since they do not override the inherited method (occupy the same vmt slot as the inherited method), they do not participate in polymorphic calls to the inherited method.

Possible Enhancements

Multicast events

With multicast events, you can have multiple listeners for each event. This event model is different from the Win32 event model, where an event is consumed and discarded by the first component responding to it. With event listeners, multiple components can respond to the same message (for example, all controls could respond to a "repaint" event).

In this event listener model, you can only remove your own listener. Include() and Exclude() are standard procedures overloaded to operate on events for adding or removing an event listener. Traditional singleton event semantics are supported through := assignments. If a singleton event is used with an assignment, it overrides Include() or other listeners.

Support for multicast events in Delphi for .NET is a requirement. Support for multicast events may appear in future releases of Delphi for Win32 and Linux.

Interface method resolution

Interface method resolution provides a convenient shorthand for implementing methods referenced in an interface. By default, the compiler attempts to bind a method name to a method of the same name in the class implementing the interface. With the following code,

Type

TMyClass = class(TBaseClass, IFoo)

procedure FooBar(paramlist);

procedure IFoo.Bar = FooBar;

end;

The new version would be:

Type

TMyClass = class(TBaseClass, IFoo)

procedure IFoo.Bar(paramlist);

end;

A reference to TMyClass.IFoo.Bar is then valid.

When multiple interfaces are used, interface method resolution becomes even more valuable. The following code illustrates:

IFoo1 = interface

procedure Bar;

end;

IFoo2 = interface

procedure Bar;

end;

TSomeClass = class(TBaseClass, IFoo1, IFoo2)

procedure IFoo1.Bar;

procedure IFoo2.Bar;

end;

Array property overloads

Array property overloads will also be supported. The following example shows the probable syntax for overloading array property references.

TSomeClass = class

property Item[Index: string]: string

read GetItem write SetItem; overload;

property Item[Index: integer]: string

read GetItem write SetItem; overload;

property Names: string read GetNames write SetNames;

overload;

property Names[Index: Integer]: string

read GetNames write SetNames; overload;

function GetItem(Index: string): string; overload;

procedure SetItem(Index:string; Value: string); overload;

function GetItem(Index: Integer): string;

overload;

procedure SetItem(Index: Integer; Value: string);

overload;

function GetNames: string; overload;

procedure SetNames(Value: string); overload;

function GetNames(Index: Integer): string;

overload;

procedure SetNames(Index: Integer; Value: string);

overload;

end;

Overload of array properties is required for CLS compliance. For example, the CLR NameValueCollection overloads integer and string index references for the default Item property, as does this code snippet example above.

Conclusion

This document is intended to introduce some of the new features and concepts under research for the Delphi for .NET compiler. While every attempt has been made to keep this information accurate, all of it is subject to change. Compiler support for .NET has provided some exciting opportunities for enhancement to the Delphi language. The language enhancements discussed here are for the Delphi for .NET compiler unless otherwise stated. Hopefully, you like what you see so far.

Stay tuned to this web site, as more articles on Delphi for .NET are coming very soon.

Add or View comments on this article

Article ID: 28972 Publish Date: August 06, 2002 Last Modified: August 05, 2002

Help

Feedback

Home Pages

Newsgroups

Search

Made in Borland® Copyright© 1994-2002 Borland Software Corporation. All rights reserved. Legal Notices, Privacy Policy

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有