WinRT语言投影是什么?

30

WinRT语言投影是什么,它们有什么用处?

4个回答

20

Windows Runtime投影是将Windows Runtime API在每种编程语言中的暴露方式。这可能是在编译时(如C ++)或运行时(如JavaScript)或两者的组合(如C#)。每种语言都决定如何最好地呈现WinRT APIs。大部分情况下,它是直接暴露,但有时可能会发生封装或重定向。代理和事件是一个很好的例子。在C#中,它们显示为C#委托/事件,而不是WinRT特定的类型。同样,字符串被重新映射为本地语言字符串类型,而不是基础的hstring类型。


19

"Projections" 在 WinRT 中是 "Bindings" 的另一个说法。

WinRT 语言投影是针对每种支持的语言的 WinRT 绑定。

了解更多信息,请查看:

WinRT 解密 - Miguel de Icaza


3
一个微妙的区别是,“绑定(bindings)”可以手动完成,而“投影(projections)”总是自动化的。也就是说,使用投影时,您不需要手动编写用于 WinRT 的 FFI 声明,只需使用一次编写的代码,将任何 WinRT 组件暴露给所涉语言,并使用该语言的惯用语来进行操作即可。 - Pavel Minaev

10

语言投影是一种以友好的方式向您展示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();

Pascal版构造函数

假设你正在使用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 接口中,您必须使用以下方法来获取和设置属性:

  • get_Year
  • set_Year

如果您盲目地将其翻译为 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;

迭代器(ITerators)

迭代器的概念是创建一个表面看起来和你的语言相似的外观,但在背后,它将映射回底层的调用。这个概念非常深刻。

在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); }
}

然而,在其他语言中,我们已经有了自己的日期时间类:

  • C#: System.DateTimeOffset
  • Javascript: Date
  • C++: FILETIME
  • Delphi: 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#中,没有人实际编写投影版本;编译器和运行时在后台执行所有工作,因为它知道如何读取元数据。

对于其他语言,翻译的代码文件可以手动创建,也可以通过导入工具自动创建。


5

最简单的解释是,WinRT中的语言投影是“前端”,而Windows Runtime是后端。从这三种语言(JS、C#、VB)中编写代码,在后端的行为是完全相同的。

如果你使用C++或C#编写自己的第三方WinRT组件,可以在JS、C#和VB中使用它,而不需要额外的工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接