WinRT语言投影是什么,它们有什么用处?
Windows Runtime投影是将Windows Runtime API在每种编程语言中的暴露方式。这可能是在编译时(如C ++)或运行时(如JavaScript)或两者的组合(如C#)。每种语言都决定如何最好地呈现WinRT APIs。大部分情况下,它是直接暴露,但有时可能会发生封装或重定向。代理和事件是一个很好的例子。在C#中,它们显示为C#委托/事件,而不是WinRT特定的类型。同样,字符串被重新映射为本地语言字符串类型,而不是基础的hstring类型。
"Projections" 在 WinRT 中是 "Bindings" 的另一个说法。
WinRT 语言投影是针对每种支持的语言的 WinRT 绑定。
了解更多信息,请查看:
语言投影是一种以友好的方式向您展示Windows Runtime 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); }
}
}
Pascal:
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 Holidays
(在假期中循环日期)for 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); }
}
然而,在其他语言中,我们已经有了自己的日期时间类:
System.DateTimeOffset
Date
FILETIME
TDateTime
因此,投影会将WinRT DateTime
(自1601年1月1日以来100纳秒间隔的Int64数字)转换为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 Runtime是后端。从这三种语言(JS、C#、VB)中编写代码,在后端的行为是完全相同的。
如果你使用C++或C#编写自己的第三方WinRT组件,可以在JS、C#和VB中使用它,而不需要额外的工作。