Языковая проекция - это способ познакомить вас с API среды выполнения Windows без использования языков.
Например, лежащий в основе способ создания 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();
Если вы в Паскале, у вас есть:
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: у вас уже есть идиома для создания объектов. Позволяет преобразовать основную сантехнику в дружественную проекцию Паскаля:
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;
И теперь у нас есть проекция Дельфи :
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 все перечисляемое реализует
Но в C # все перечисляемое должно начинаться с:
Таким образом, библиотека .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); }
}
Но на других языках у нас уже есть свои datetime классы:
- C # :
System.DateTimeOffset
- Javascript :
Date
- C ++ :
FILETIME
- Delphi :
TDateTime
Таким образом, проекция выполняет преобразование WinRT DateTime
(Int64, который является числом интервалов 100 нс с 1 января 1601 г.) в 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 # никто на самом деле не пишет прогнозируемые версии; компилятор и среда выполнения выполняют всю работу за кулисами, поскольку умеют читать метаданные.
Для других языков переведенные файлы кода создаются вручную или автоматически с помощью инструмента импорта.