【问题标题】:What are WinRT language projections?什么是 WinRT 语言投影?
【发布时间】:2011-09-15 14:52:51
【问题描述】:

什么是 WinRT 语言投影以及它们的用途?

【问题讨论】:

    标签: windows-runtime


    【解决方案1】:

    WinRT 中的“Projections”是“Bindings”的另一种说法。

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

    欲了解更多信息,请查看:

    WinRT Demystified - Miguel de Icaza

    【讨论】:

    • 一个细微的区别是“绑定”可以是手动的,而“投影”始终是自动的——也就是说,您不必坐在那里手动为 WinRT 编写带有投影的 FFI 声明,您只需使用代码,编写一次,它采用任何 WinRT 组件并使用该语言的习语将其公开给相关语言。
    【解决方案2】:

    Windows 运行时投影是在每种语言中公开 Windows 运行时 API 的方式。这可能是在编译时(如在 C++ 中)或在运行时(如在 JavaScript 中)或组合时(如在 C# 中)。每种语言都决定如何最好地呈现 WinRT API。大多数时候是直接暴露,但其他时候可能会发生包装或重定向。代表和活动就是一个很好的例子。在 C# 中,它们显示为 C# 委托/事件,而不是特定于 WinRT 的类型。字符串同样被重新映射为本地语言字符串类型,而不是底层的 hstring 类型。

    【讨论】:

      【解决方案3】:

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

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

      帕斯卡

      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&lt;T&gt;

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

      但在其他语言中,我们已经有了自己的 datetime 类:

      • C#System.DateTimeOffset
      • JavascriptDate
      • C++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;    
      

      tl;博士

      投影是 WinRT 周围的一组包装器,使其看起来尽可能像您的母语。

      在 C# 中,实际上没有人编写计划版本;编译器和运行时在幕后完成所有工作,因为它知道如何读取元数据。

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

      【讨论】:

        【解决方案4】:

        最简单的澄清方法是,WinRT 中的语言投影是“前端”,而 Windows 运行时是后端。使用三种语言(JS、C#、VB)中的一种编写,它在后端的行为相同。

        如果您使用 C++ 或 C# 编写自己的 3rd Party WinRT 组件,则可以在 JS、C# 和 VB 中使用它,而无需做任何额外的工作。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-01-25
          • 1970-01-01
          • 2017-02-15
          • 1970-01-01
          • 2018-08-18
          • 2010-11-05
          • 2014-06-08
          • 2011-04-21
          相关资源
          最近更新 更多