クロスプラットフォーム開発のためのCSCSスクリプト言語の使用
公開: 2022-03-10私たちの目標は、プラットフォームを構築することではありません。 それらすべてを横断することです。
- マーク・ザッカーバーグ
CSCS(Customized Scripting in 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 StudioXamarinプロジェクトに埋め込むことでプロジェクトに追加できます。 他のほとんどの言語とは異なり、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); }
以下の画像は、「こんにちは」ボタンをクリックし、「テキスト編集」フィールドに何も入力しなかった後の、iPhoneおよびAndroidデバイスでの結果のユーザーインターフェイスを示しています。
上記のコードを簡単に見てみましょう。 AutoScale()
関数呼び出しから始まり、ウィジェットのサイズが画面サイズに相対的であること、つまり自動サイズ変更されることをパーサーに通知します(ウィジェットは大きな画面では大きく見え、小さい画面では小さく見えます)。画面)。 この設定は、ウィジェットごとにオーバーライドすることもできます。
ボタンクリックで特別なハンドラーを作成する必要がないことに注意してください。 widgetName_click()
という名前の関数を定義すると、ユーザーがwidgetName
というウィジェットをクリックしたときにハンドラーとして使用されます(ボタンである必要はなく、実際には任意のウィジェットにすることができます)。 そのため、ユーザーがボタンをクリックするとすぐに関数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)
を呼び出すことでいつでも変更できます。
VisualStudioコードを使用したCSCSのデバッグ
Visual StudioCodeを使用してCSCSスクリプトをデバッグすることもできます。 AndroidとiOSの両方のアプリを開発する場合は、Macを使用する必要があります。 Visual Studio Codeをインストールした後、CSCSデバッガーとREPL拡張機能をインストールします。
拡張機能を使用するには、 start.cscs
スクリプトの任意の場所に次のコード行を追加します。
StartDebugger();
次の画像は、Visual Studio Codeを使用して「Hello、World!」の機能をデバッグおよび変更する方法を示しています。 前のセクションで開発したアプリ。 次の例では、既存のレイアウトにラベルとボタンをその場で追加します。
これを行うには、パーサーによって実行されるコードを選択し、 Ctrl +8を押します。 その結果、画面中央にラベルとボタンが追加されます。 また、ボタンがクリックされるたびに現在の時刻で新しいラベルを更新するボタンハンドラーを追加します。
CSCSでのSQLiteの使用
SQLiteは、ACID(Atomicity、Consistency、Isolation、Durability)タイプのリレーショナルデータベースであり、Richard Hippによって開発されました(最初のバージョンは2000年にリリースされました)。 Microsoft SQLServerやOracleDatabaseなどの他のリレーショナルデータベースとは異なり、組み込みです。 (デバイスだけでなく、エンドプログラムにも組み込まれています。)サイズが500KB未満の非常にコンパクトなライブラリとしてプログラムに含まれています。 ただし、DBファイルパスが両方のアプリに認識されている場合、2つのアプリ(同じ開発者によってリリースされた)は同じSQLiteDBを読み取ることができます。
SQLiteの利点は、iOSまたはAndroidデバイスに追加インストールせずに使用できることです。 欠点は、明らかに「通常の」DBほど多くのデータを保持できないことと、型が弱いことです(つまり、整数の代わりに文字列を挿入できます。失敗すると、整数または0に変換されます)。 一方、後者も利点と見なすことができます。
SQLiteは、追加のインポートステートメントなしでCSCSから簡単に使用できます。 CSCSで使用される主なSQLite関数の概要を理解するのに役立つ表を次に示します。
指示 | 説明 |
---|---|
SQLInit(DBName) | データベースを初期化するか、結果として生じるDBステートメントで使用されるデータベースを設定します。 |
SQLDBExists(DBName) | DBが初期化されているかどうかを確認します。 また、結果として生じる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スリープ機能の既存の実装を以下に示します。
カスタム機能を追加するには、 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; } }
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
、 function
、 include
、 new
、 class
、 return
、 try
、 throw
、 catch
、 break
、 continue
)。 これは、「sleep(100)」または「Sleep(100)」のいずれかを入力できることを意味します。どちらの呼び出しも、実行中のスレッドを100ミリ秒中断します。
CSCSでのJSONの処理
JSON(JavaScript Object Notation)は、属性と値のペアと配列型のペアで構成される軽量のデータ交換形式です。 これは、2000年代初頭にDouglas Crockfordによって開発されました(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サービスからJSON文字列を解析する別の例を見ていきます。
SQLite、Webリクエスト、JSONを使用したアプリの例
SQLite、Webサービス、およびJSON解析を使用するアプリの場合、Alpha VantageWebサービスを使用します。 APIキーは無料で入手できますが、無料バージョンでは1分間に5回までWebサービスにアクセスできます。
Alpha Vantageを使用すると、株価などのさまざまな財務データセットを抽出できます。 これは、サンプルアプリで行うことです。
下の画像は、iOSおよびAndroidデバイスでのStocksアプリの外観を示しています。
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 VantageWebサービスからデータを取得する方法を見てみましょう。 まず、データを初期化します。
baseURL = "https://www.alphavantage.co/query? " + "function=TIME_SERIES_DAILY&symbol="; apikey = "Y12T0TY5EUS6BC5F"; stocks = {"MSFT", "AAPL", "GOOG", "FB", "AMZN"}; totalStocks = stocks.Size;
次に、ユーザーが「更新」ボタンをクリックするとすぐに、株を1つずつロードします。
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");
最後の2つのパラメーターは、Web要求の完了時に呼び出す関数です。 たとえば、障害が発生した場合、次のCSCS関数が呼び出されます。
function OnFailure(object, errorCode, text) { SetText(labelError, text); lockGui(false); }
その結果、ユーザーには次のようなエラーメッセージが表示されます。
ただし、問題がなければ、JSON文字列を解析し、その内容をSQLiteDBに挿入します。
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 VantageWebリクエストから受信した実際の文字列を見てみましょう。
{ "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を追加するのは簡単です。 サンプルのXamarinプロジェクトで行うのと同じように、CSCSのソースコードをモジュールとしてプロジェクトに埋め込むだけです。
プロジェクトでCSCSスクリプト言語を使用および拡張していますか? 以下にコメントを残してください—私はあなたから聞いてうれしいです!
参考文献
CSCS言語をもう少し詳しく知りたい場合は、このトピックについて私が書いた記事のいくつかを次に示します。
- 「C#での分割およびマージ式パーサー」、MSDN Magazine(2015年10月)
- 「C#でのカスタマイズ可能なスクリプト」、MSDN Magazine(2016年2月)
- 「カスタマイズ可能なスクリプト言語を使用したネイティブモバイルアプリの作成」、MSDN Magazine(2018年2月)
- 「CSCS:C#でカスタマイズされたスクリプト」、GitHub
- 「機能的なスクリプト言語を使用したクロスプラットフォームのネイティブアプリの開発」、CODE Magazine
- 「カスタム言語を簡潔に実装する」(eBook)
- 「関数型言語でネイティブモバイルアプリを簡潔に書く」(eBook)
追加のリソースとして、CSCSの関数を事前にコンパイルしてCSCSのパフォーマンスを向上させる方法も読むことをお勧めします。