【发布时间】:2011-09-15 14:52:51
【问题描述】:
什么是 WinRT 语言投影以及它们的用途?
【问题讨论】:
标签: windows-runtime
什么是 WinRT 语言投影以及它们的用途?
【问题讨论】:
标签: windows-runtime
WinRT 中的“Projections”是“Bindings”的另一种说法。
WinRT 语言投影是支持的每种语言的 WinRT 绑定。
欲了解更多信息,请查看:
【讨论】:
Windows 运行时投影是在每种语言中公开 Windows 运行时 API 的方式。这可能是在编译时(如在 C++ 中)或在运行时(如在 JavaScript 中)或组合时(如在 C# 中)。每种语言都决定如何最好地呈现 WinRT API。大多数时候是直接暴露,但其他时候可能会发生包装或重定向。代表和活动就是一个很好的例子。在 C# 中,它们显示为 C# 委托/事件,而不是特定于 WinRT 的类型。字符串同样被重新映射为本地语言字符串类型,而不是底层的 hstring 类型。
【讨论】:
语言投影是一种以语言友好的方式向您展示 Windows 运行时 API 的方法。
例如,创建Windows.Globalization.Calendar对象的底层方法是调用:
IInspectable instance;
HRESULT hr = RoActivateInstance(StringToHSTRING("Windows.Globalization.Calendar"), out instance);
if (Failed(hr))
throw new ComException(hr);
ICalendar calendar;
hr = instance.QueryInterface(IID_ICalendar, out calendar);
if (Failed(hr))
throw new ComException(hr);
这就是大多数语言所称的“构造函数”。但是大多数语言已经有了“创建对象”的语法。
如果你使用 C#,你有:
Calendar calendar = new Calendar();
如果你在 Pascal 中,你有:
calendar: TCalendar;
calendar := TCalendar.Create;
所以让我们围绕这个创建一个类似 C# 的包装器(或 投影):
class Calendar : Object
{
private ICalendar _calendar;
//constructor
void Calendar() : base()
{
IInspectable instance;
HRESULT hr = RoActivateInstance(StringToHSTRING("Windows.Globalization.Calendar"), out instance);
if (Failed(hr))
throw new ComException(hr);
ICalendar calendar;
hr = instance.QueryInterface(IID_ICalendar, out calendar);
if (Failed(hr))
throw new ComException(hr);
this._calendar = calendar;
}
}
现在您可以使用友好的类似 C# 的投影了:
Calendar cal = new Calendar();
假设您正在使用 Delphi:您已经有一个用于创建对象的习惯用法。让我们将底层管道转换为友好的 Pascal 投影:
TCalendar = class
private
FCalendar: ICalendar;
public
constructor Create;
end;
constructor TCalendar.Create;
var
instance: IInspectable;
calendar: ICalendar;
hr: HRESULT;
begin
inherited Create;
hr := RoActivateInstance(StringToHSTRING('Windows.Globalization.Calendar'), {out} instance);
OleCheck(hr);
hr = instance.QueryInterface(IID_ICalendar, {out} calendar);
OleCheck(hr);
FCalendar := calendar;
end;
现在我们有了 Delphi 投影:
calendar: TCalendar;
calendar := TCalendar.Create;
在底层的ICalendar接口中,你必须使用方法来获取和设置属性:
如果你盲目地将它翻译成 C#,你会得到:
C#属性方法:
class Calendar : Object
{
private ICalendar _calendar;
public int get_Year() { return _calendar.get_Year(); }
void set_Year(int value) { _calendar.set_Year(value); }
}
Pascal 属性方法:
TCalendar = class
public
function get_Year: Integer;
procedure set_Year(Value: Integer);
end;
但如果您的语言支持它们,您实际上应该将这些属性公开为实际的“属性”。所以我们可以使用我们语言原生的属性语法来投影这些属性:
C#:
class Calendar : Object
{
private ICalendar _calendar;
public int Year {
get { return _calendar.get_Year(); }
set { _calendar.set_Year(value); }
}
}
帕斯卡:
TCalendar = class
public
property Year: Integer read get_Year write set_Year;
end;
这个想法是创建一个外观和感觉都像您的语言的外观,但在幕后它映射回底层调用。它很深。
在 WinRT 中,所有可枚举的实现
IIterable<T>但是在 C# 中,所有可枚举的东西都应该从:
IEnumerable所以 .NET 库有一个内部类,它适应 IIterable<T> 并将其公开为 IEnumerable。
所以不是返回IIterable<T>的方法:
class Calendar : Object
{
public IIterable<Datetime> Holidays()
{
return _calendar.Holidays();
}
}
它返回一个IEnumerable<T>:
class Calendar : Object
{
public IEnumerable<DateTime> Holidays()
{
IIterable<DateTime> iter = _calendar.Holidays();
//Create helper class to convert IIterable to IEnumerable
IEnumerable<DateTime> enum = new IteratorToEnumeratorAdapter(iter);
return enum;
}
}
这样你就可以使用你自己的语言了:
foreach date in Holidaysfor date in Holdays do在 WinRT 中,日期表示为 Windows.Foundation.DateTime:
class Calendar : Object
{
//Windows.Foundation.DateTime
Datetime Date { get { return _calendar.get_Date(); } set { _calendar.set_Date(value); }
}
但在其他语言中,我们已经有了自己的 datetime 类:
System.DateTimeOffset
Date
FILETIME
TDateTime
因此,投影完成了将 WinRT DateTime(一个 Int64,即自 1601 年 1 月 1 日以来的 100ns 间隔数)转换为 C# DateTimeOffset 的工作:
class Calendar : Object
{
//System.DateTimeOffset
DateTimeOffset Date {
get {
Int64 ticks _calendar.get_Date().UniversalTime();
DateTimeOffset dt = DateTimeOffset.FromFileTime(ticks);
return dt;
}
set {
Int64 ticks = value.ToFileTime();
DateTime dt = new Windows.Foundation.DateTime();
dt.UniversalTime = ticks;
_calendar.set_Date(dt);
}
}
还有类似于 Delphi 的 TDateTime:
type
TCalendar = class(TObject)
private
FCalendar: ICalendar;
function getDate: TDateTime;
procedure setDate(Value: TDateTime);
public
property Date: TDateTime read getDate write setDate;
end;
function TCalendar.GetDate: TDateTime;
var
ticks: Int64;
const
OA_ZERO_TICKS = Int64(94353120000000000);
TICKS_PER_DAY = Int64(864000000000);
begin
ticks := FCalendar.get_Date().UniversalTime;
Result := (ticks - OA_ZERO_TICKS) / TICKS_PER_DAY;
end;
procedure TCalendar.SetDate(Value: TDateTime);
var
ticks: Int64;
const
OA_ZERO_TICKS = Int64(94353120000000000);
TICKS_PER_DAY = Int64(864000000000);
begin
ticks := (Value * TICKS_PER_DAY) + OA_ZERO_TICKS;
FCalendar.set_Date(Round(ticks));
end;
投影是 WinRT 周围的一组包装器,使其看起来尽可能像您的母语。
在 C# 中,实际上没有人编写计划版本;编译器和运行时在幕后完成所有工作,因为它知道如何读取元数据。
对于其他语言,翻译后的代码文件可以手动创建,也可以通过导入工具自动创建。
【讨论】:
最简单的澄清方法是,WinRT 中的语言投影是“前端”,而 Windows 运行时是后端。使用三种语言(JS、C#、VB)中的一种编写,它在后端的行为相同。
如果您使用 C++ 或 C# 编写自己的 3rd Party WinRT 组件,则可以在 JS、C# 和 VB 中使用它,而无需做任何额外的工作。
【讨论】: