个性化阅读
专注于IT技术分析

使用CSCS脚本语言进行跨平台开发

点击下载

我们的目标不是建立平台,而是要跨越所有人。 – 马克·扎克伯格

CSCS(C#中的自定义脚本)是一种用C#实现的开源脚本语言。从语法上讲, 它与JavaScript非常相似, 但与Python也有一些相似之处。其中一些相似之处是著名的if … elif … else构造中的关键字, 并且具有与Python中相同的变量范围定义(例如, 在if块内部或循环内部定义的变量在外部也可见) 。

与JavaScript和Python相反, CSCS中的变量和函数不区分大小写。 CSCS的主要目标是让开发人员编写尽可能少的代码。同样, 相同的代码用于iOS和Android开发。此外, CSCS可用于Windows, Mac和Unity开发。

注意:你可以在此处详细了解Microsoft如何在其Maquette产品(基于Unity)中使用CSCS。

通过将CSCS的C#源代码嵌入到Visual Studio Xamarin项目中, 可以将CSCS添加到你的项目中。与大多数其他语言不同, 你拥有CSCS源代码的完全所有权, 可以轻松添加或修改其功能。稍后, 我将在此分享一个示例。

另外, 我们还将学习如何开始使用CSCS, 以及如何使用其他文章中介绍的一些更高级的功能。在这些功能中, 我们将使用JSON字符串解析通过Web请求访问Web服务, 并且还将在iOS和Android上使用SQLite。

最简单的入门方法是使用CSCS下载项目示例, 然后开始使用start.cscs文件播放。这是我们在下一部分中要执行的操作:创建具有基本GUI和事件的iOS / Android应用。

“你好, 世界!”在CSCS中

让我们从一个相对简单的CSCS代码示例开始, 该示例构建一个带有一些小部件的屏幕:

AutoScale();
SetBackgroundColor("light_green");

locLabelText = GetLocation("ROOT", "CENTER", "ROOT", "TOP");
AddLabel(locLabelText, "labelText", "Welcome " +
    _DEVICE_INFO_ + " " + _VERSION_INFO_ + " User!", 600, 100);

locTextEdit = GetLocation("ROOT", "LEFT", labelText, "BOTTOM");
AddTextEdit(locTextEdit, "textEdit", "Your name", 320, 80);

locButton = GetLocation(textEdit, "RIGHT", textEdit, "CENTER");
AddButton(locButton, "buttonHi", "Hello", 160, 80);

function buttonHi_click(sender, arg) {
  name = getText(textEdit);
  msg = name != "" ? "Hello, "+ name + "!" : "Hello, World!";
  AlertDialog("My Great App", msg);
}

下图显示了在单击“ Hello”按钮并且未在“ Text Edit”字段中键入任何内容之后在iPhone以及Android设备上生成的用户界面:

hello world在iPhone(左)和Android(右)上

“你好, 世界!”在iPhone(左)和Android(右)上(

大型预览

)

让我们简单地回顾一下上面的代码。它从AutoScale()函数调用开始, 其作用是告诉解析器小部件尺寸与屏幕尺寸有关, 即它们将自动调整大小(小部件在大屏幕上看起来更大, 在小屏幕上看起来更小)屏幕)。每个窗口小部件也可以覆盖此设置。

请注意, 无需在单击按钮时创建特殊的处理程序。如果你定义一个名为widgetName_click()的函数, 则当用户单击名为widgetName的widget时, 它将用作处理程序(它不一定是按钮, 实际上可以是任何widget)。这就是为什么用户单击按钮后立即触发按钮buttonHi_click()的原因。

你可能已经注意到GUI是完全用代码构造的。这是通过在添加时提供相对的窗口小部件位置来完成的。位置命令的一般格式如下:

location = GetLocation(WidgetX, HorizontalPlacement, WidgetY, VerticalPlacement, deltaX=0, deltaY=0, autoResize=true);

因此, 你可以在屏幕上放置相对于其他窗口小部件的窗口小部件。小部件的一个特殊情况是“ ROOT”小部件, 即主屏幕。

创建位置后, 需要将其作为以下任何函数的参数提供:

  • AddLabel,
  • AddButton,
  • AddCombobox,
  • AddStepper,
  • AddListView,
  • AddTextView,
  • AddStepper,
  • AddImageView,
  • AddSlider,
  • AddPickerView,
  • 等等。

以上所有结构都相同:

AddButton(location, newWidgetname, initialValue, width, height);

如果先前运行了AutoScale()CSCS命令, 则小部件的宽度和高度将相对于屏幕大小。同样, 初始值(在按钮的情况下)是其上显示的文本。可以通过调用SetText(widgetName, newText)随时更改此设置。

使用Visual Studio代码调试CSCS

我们还可以使用Visual Studio Code调试CSCS脚本。如果要为Android和iOS开发应用程序, 则需要使用Mac。安装Visual Studio Code后, 请安装CSCS调试器和REPL扩展。

为了使用扩展名, 请将以下代码行添加到start.cscs CSCS脚本中的任何位置:

StartDebugger();

下图显示了如何使用Visual Studio Code调试和更改“ Hello, World!”的功能。我们在上一节中开发的应用程序。在接下来的示例中, 我们将即时向现有布局添加标签和按钮。

为此, 我们只需选择要由解析器执行的代码, 然后按Ctrl +8。结果, 标签和按钮将添加到屏幕中央。我们还添加了一个按钮处理程序, 它将在每次按钮单击时使用当前时间更新新标签。

使用Visual Studio Code即时更改布局

使用Visual Studio Code即时更改布局(

大型预览

)

在CSCS中使用SQLite

SQLite是关系数据库的ACID(原子性, 一致性, 隔离性, 耐久性)类型, 由Richard Hipp开发(第一个版本于2000年发布)。与其他关系数据库(例如Microsoft SQL Server或Oracle数据库)不同, 它是嵌入式的。 (不仅包含在设备中, 而且包含在最终程序中。)它作为一个非常紧凑的库包含在程序中, 它的大小小于500 KB。但是, 如果两个应用程序都知道数据库文件路径, 则两个应用程序(由同一个开发人员发布)可以读取相同的SQLite DB。

SQLite的优势在于, 无需在iOS或Android设备上进行额外安装即可使用它。缺点是, 它显然不能容纳“普通”数据库那么多的数据, 而且类型也很弱(即, 你可以插入字符串而不是整数-如果失败, 则将其转换为整数或0)。另一方面, 后者也可以看作是一种优势。

从CSCS可以轻松使用SQLite, 而无需额外的导入语句。这是一张表格, 可帮助你大致了解CSCS中使用的主要SQLite函数:

命令 描述
SQLInit(DBName) 初始化数据库或设置数据库以供随后的DB语句使用。
SQLDBExists(DBName) 检查数据库是否已初始化。还设置要与后续DB语句一起使用的数据库。
SQLQuery(query) 执行一个SQL查询(一条select语句)。返回带有记录的表。
SQLNonQuery(nonQuery) 执行SQL非查询, 例如更新, 创建或删除语句。返回受影响的记录数。
SQLInsert(tableName, columnList, data) 将传递的记录数据表插入指定的DB表。 columnList参数具有以下结构:colName1, colName2, …, colNameN

表1:CSCS中的SQLite命令

通常这样使用SQLInit()和SQLDBExists()函数:

DBName = "myDB.db1";

if (!SQLDBExists(DBName)) {
  create = "CREATE TABLE [Data] (Symbol ntext, Low real, High real, Close real, Volume real, Stamp text DEFAULT CURRENT_TIMESTAMP)";
  SQLNonQuery(create);
}


SQLInit(DBName);

我们将在以后看到更多有关如何选择数据并将其插入SQLite数据库的示例。我将向你展示一个示例, 该示例说明如何将从Web服务中提取的库存数据写入本地SQLite数据库。

向CSCS添加自定义功能

在本节中, 我们将看到如何扩展CSCS功能。作为示例, 我们将在下面看到CSCS Sleep函数的现有实现。

要添加自定义功能, 你所需要做的就是通过派生自ParserFunction类, 重写其Evaluate()方法并向解析器注册该类来创建一个新类。这是一个简短的版本(不进行错误检查):

class SleepFunction : ParserFunction
{
  protected override Variable Evaluate(ParsingScript script)
  {
    List  args = script.GetFunctionArgs();
    int sleepms = Utils.GetSafeInt(args, 0);
    Thread.Sleep(sleepms);

    return Variable.EmptyInstance;
  }
}

可以使用以下命令在初始化阶段中的任何位置完成向解析器注册类的操作:

ParserFunction.RegisterFunction("Sleep", new SleepFunction());

而已!现在, 解析器提取“ Sleep”令牌后, 将立即调用SleepFunction类的Evaluate()方法。

请注意, CSCS不区分大小写(核心控制流语句除外:if, elif, else, for, while, 函数, include, new, class, return, try, throw, catch, break, continue)。这意味着你可以键入“ sleep(100)”或“ Sleep(100)”, 这两个调用都将使执行线程挂起100毫秒。

在CSCS中处理JSON

JSON(JavaScript对象表示法)是一种轻量级的数据交换格式, 由属性值对和数组类型对组成。它由道格拉斯·克罗克福德(Douglas Crockford)在2000年代初期(大约在SQLite出现的同一时间)开发。

在本节中, 我们将学习如何使用CSCS解析JSON。

解析JSON字符串的CSCS函数是GetVariableFromJSON(jsonText)。此函数返回一个哈希表, 其中的键是JSON字符串中的属性。

考虑以下JSON字符串示例:

jsonString = '{ "eins" : 1, "zwei" : "zweiString", "mehr" : { "uno": "dos" }, "arrayValue" : [ "une", "deux" ] }';

调用后:

a = GetVariableFromJSON();

变量a将是具有以下值的哈希表:

a["eins"] = 1
a["zwei"] = "zweiString"
a["mehr"]["uno"] = "dos"
a["arrayValue"][0] = "une"
a["arrayValue"][1] = "deux"

在下一节中, 我们将看到另一个从Web Service解析JSON字符串的示例。

带有SQLite, Web请求和JSON的应用示例

对于使用SQLite, Web服务和JSON解析的应用程序, 我们将使用Alpha Vantage Web服务。你可以免费获得API密钥, 但免费版本允许每分钟访问其Web服务的次数不超过5次。

使用Alpha Vantage, 你可以提取各种财务数据集-包括股票价格。这就是我们将在示例应用程序中执行的操作。

下图显示了Stocks应用在iOS和Android设备上的外观。

从iOS(左)和Android(右)上的Alpha Vantage Web Service提取

从iOS(左)和Android(右)的Alpha Vantage Web Service提取股票(

大型预览

)

用于构建GUI的CSCS代码如下:

locLabel = GetLocation("ROOT", "CENTER", "ROOT", "TOP", 0, 30);
AddLabel(locLabel, "labelRefresh", "", 480, 60);

locSFWidget = GetLocation("ROOT", "CENTER", labelRefresh, "BOTTOM");
AddSfDataGrid(locSFWidget, "DataGrid", "", graphWidth, graphHeight);

listCols = {"Symbol", "string", "Low", "number", "High", "number", "Close", "number", "Volume", "number"};
AddWidgetData(DataGrid, listCols, "columns");
colWidth = {17, 19, 19, 19, 26};
AddWidgetData(DataGrid, colWidth, "columnWidth");

locButton = GetLocation("ROOT", "CENTER", DataGrid, "BOTTOM");
AddButton(locButton, "buttonRefresh", "Refresh", 160, 80);

locLabelError = GetLocation("ROOT", "CENTER", "ROOT", "BOTTOM");
AddLabel(locLabelError, "labelError", "", 600, 160);
SetFontColor(labelError, "red");
AlignText(labelError, "center");

getDataFromDB();

getDataFromDB()方法将从SQLite数据库中提取所有数据。它使用如下定义的SQL查询:

query = "SELECT Symbol, Low, High, Close, Volume, DATETIME(Stamp, 'localtime') as Stamp FROM Data ORDER BY Stamp DESC LIMIT 5;";

查看下面的getDataFromDB()实现代码。

function getDataFromDB() {
  results = SQLQuery(query);
  for (i = 1; i < results.Size; i++) {
    vals       = results[i];
    stock      = vals[0];
    low        = Round(vals[1], 2);
    high       = Round(vals[2], 2);
    close      = Round(vals[3], 2);
    volume     = Round(vals[4], 2);
    refresh    = vals[5];

    stockData  = {stock, low, high, close, volume};
    AddWidgetData(DataGrid, stockData, "item");
  }
  SetText(labelRefresh, "DB Last Refresh: " + refresh);
  lockGui(false);
}

现在, 让我们看看如何从Alpha Vantage Web服务获取数据。首先, 我们初始化数据:

baseURL     = "https://www.alphavantage.co/query? " +
              "function=TIME_SERIES_DAILY&symbol=";
apikey      = "Y12T0TY5EUS6BC5F";
stocks      = {"MSFT", "AAPL", "GOOG", "FB", "AMZN"};
totalStocks = stocks.Size;

接下来, 我们在用户单击“刷新”按钮后立即逐一加载库存:

function buttonRefresh_click(object, arg) {
  lockGui();

  SetText(labelRefresh, "Loading ...");
  SetText(labelError, "");
  ClearWidget(DataGrid);
  loadedStocks = 0;
  getData(stocks[loadedStocks]);
}

function getData(symbol) {
  stockUrl  = baseURL + symbol + "&apikey=" + apikey;
  WebRequest("GET", stockUrl, "", symbol, "OnSuccess", "OnFailure");
}

这是从Web服务获取数据时要使用的主要CSCS功能:

WebRequest("GET", stockUrl, "", symbol, "OnSuccess", "OnFailure");

最后两个参数是在Web请求完成时调用的函数。例如, 如果发生故障, 将调用以下CSCS函数:

function OnFailure(object, errorCode, text)
{
  SetText(labelError, text);
  lockGui(false);
}

结果, 用户将收到一条错误消息, 如下所示:

请求网络数据时出错

请求网络数据时出错(

大型预览

)

但是, 如果一切都很好, 我们将解析JSON字符串并将其内容插入SQLite DB。

function OnSuccess(object, errorCode, text)
{
  jsonFromText  = GetVariableFromJSON(text);
  metaData      = jsonFromText[0];
  result        = jsonFromText[1];

  symbol        = metaData["2. Symbol"];
  lastRefreshed = metaData["3. Last Refreshed"];
  allDates      = result.keys;

  dateData   = result[allDates[0]];
  high       = Round(dateData["2. high"], 2);
  low        = Round(dateData["3. low"], 2);
  close      = Round(dateData["4. close"], 2);
  volume     = dateData["5. volume"];
  stockData  = {symbol, low, high, close, volume};
  SQLInsert("Data", "Symbol, Low, High, Close, Volume", stockData);

  if (++loadedStocks >= totalStocks) {
    getDataFromDB();
  } else {
    getData(stocks[loadedStocks]);
  }
}

为了了解我们如何访问上面的哈希表中的不同字段, 让我们看一下从Alpha Vantage网络请求中收到的实际字符串:

{   "Meta Data": {
        "1. Information": "Daily Prices (open, high, low, close) and Volumes", "2. Symbol": "MSFT", "3. Last Refreshed": "2019-10-02 14:23:20", "4. Output Size": "Compact", "5. Time Zone": "US/Eastern"
    }, "Time Series (Daily)": {
        "2019-10-02": {
            "1. open": "136.3400", "2. high": "136.3700", "3. low": "133.5799", "4. close": "134.4100", "5. volume": "11213086"
        }, …
    }
}

如你所见, 我们将最新日期作为allDates数组的第一个元素, 该数组包含所有提取的日期。

结论

将CSCS添加到你的项目很容易。你所需要做的只是将CSCS的源代码作为模块嵌入到你的项目中, 就像在Xamarin示例项目中一样。

你是否在项目中使用和扩展了CSCS脚本语言?在下面发表评论-我们很高兴收到你的来信!

赞(0)
未经允许不得转载:srcmini » 使用CSCS脚本语言进行跨平台开发

评论 抢沙发

评论前必须登录!