Verwendung von JSValue
Architekturbewertung erforderlich: Diese Dokumentation wurde zur Unterstützung der Entwicklung gegen die "alte" oder "Legacy"-Architektur von React Native geschrieben. Sie ist möglicherweise nicht direkt auf die Entwicklung mit der neuen Architektur anwendbar und muss überprüft und möglicherweise aktualisiert werden. Informationen zu React Native-Architekturen in React Native Windows finden Sie unter Neu vs. Alt Architektur.
Die neuesten Informationen zur nativen Entwicklung unter Windows finden Sie unter Native Plattform: Übersicht.
Diese Dokumentation und der zugrunde liegende Plattformcode sind im Entstehen begriffen.
JSValue ist ein nativer, unveränderlicher Invariant-Werttyp, der dazu dient, alle gängigen JS-Typen zu speichern: bools, ints, doubles, strings, Arrays und Objekte. Er wird für native Entwickler (die native Module oder View Manager schreiben) bereitgestellt, die eine Entsprechung zum Typ folly::dynamic wünschen, der mit der WinRT ABI-Oberfläche kompatibel ist, die von Microsoft.ReactNative bereitgestellt wird.
Es werden zwei JSValue-Implementierungen bereitgestellt: eine für C++-Entwickler im gemeinsamen Projekt Microsoft.ReactNative.Cxx und eine für C#-Entwickler im Projekt Microsoft.ReactNative.SharedManaged.
Der Zweck dieses Dokuments ist es, eine Entsprechung zu den von
folly/dynamic.hunterstützten Szenarien zu bieten.
Übersicht
Hier sind einige Codebeispiele für den Einstieg (vorausgesetzt, es wurde ein using Microsoft.ReactNative.Managed; verwendet)
JSValue twelve = 12; // creates a JSValue that holds an integer
JSValue str = "string"; // yep, this one is a String
// a few other types.
JSValue nul = JSValue.Null;
JSValue boolean = false;
// Arrays can be initialized with JSValueArray.
JSValueArray array = new JSValueArray() { "array ", "of", 4, " elements" };
Debug.Assert(array.Count == 4);
JSValueArray emptyArray = new JSValueArray();
Debug.Assert(emptyArray.Count == 0);
// JSValueArrays can be implicitly converted to JSValues, however
// like all JSValues they will be immutable. Accessing the contents
// via the AsArray() method will return an IReadOnlyList<JSValue>.
JSValue array2 = array;
Debug.Assert(array2.AsArray().Count == 4);
JSValue emptyArray2 = emptyArray;
Debug.Assert(emptyArray2.AsArray().Count == 0);
// Maps from strings to JSValues are called objects. The
// JSValueObject type is how you make an empty map from strings
// to JSValues.
JSValueObject map = new JSValueObject();
map["something"] = 12;
map["another_something"] = map["something"].AsInt32() * 2;
// JSValueObjects may be initialized this way
JSValueObject map2 = new JSValueObject()
{
{ "something", 12 },
{ "another_something", 24 },
};
// Like JSValueArrays, JSValueObjects can also be implicitly
// converted to JSValues, and likewise they will be immutable.
// Accessing the contents via the AsObject() method will return an
// IReadOnlyDictionary<string, JSValue>.
JSValue map3 = map;
Debug.Assert(map3.AsObject().Count == 2);
JSValue map4 = map2;
Debug.Assert(map4.AsObject().Count == 2);
Laufzeit-Typüberprüfung und -konvertierungen
Während die meisten nicht unterstützten Operationen zu Kompilierungsfehlern führen, erfordern einige Operationen auf JSValues eine Laufzeitprüfung, ob der gespeicherte Typ mit der Operation kompatibel ist. Einige Operationen können Laufzeitausnahmen auslösen oder unerwartetes Verhalten aufweisen, wenn Typkonvertierungen fehlschlagen und Standardwerte zurückgegeben werden.
Weitere Beispiele werden dies hoffentlich verdeutlichen
JSValue dint = 42;
JSValue str = "foo";
JSValue anotherStr = str + "something"; // fine
JSValue thisDoesNotCompile = str + dint; // compilation error
Explizite Typkonvertierungen können für einige der grundlegenden Typen angefordert werden
JSValue dint = 12345678;
JSValue doub = dint.AsDouble(); // doub will hold 12345678.0
JSValue str = dint.AsString(); // str == "12345678"
JSValue hugeInt = long.MaxValue; // hugeInt = 9223372036854775807
JSValue hugeDoub = hugeInt.AsDouble(); // hugeDoub = 9.2233720368547758E+18
Iteration und Nachschlagen
Sie können über JSValueArrays iterieren, wie Sie es über jede C#-Aufzählung tun würden.
JSValueArray array = new JSValueArray() { 2, 3, "foo" };
foreach (var val in array)
{
doSomethingWith(val);
}
Sie können über JSValueObjects wie über jede andere IDictionary<string, JSValue> iterieren.
JSValueObject obj = new JSValueObject() { { "2", 3}, { "hello", "world" }, { "x", 4 } };
foreach (var kvp in obj)
{
// Key is kvp.Key, value is kvp.Value
processKey(kvp.Key);
processValue(kvp.Value);
}
foreach (var key in obj.Keys)
{
processKey(key);
}
foreach (var value in obj.Values)
{
processValue(value);
}
Sie können ein Element anhand seines Schlüssels in einem JSValueObject mit der Methode TryGetValue() finden, die den Schlüssel nimmt und true zurückgibt, wenn ein Schlüssel vorhanden ist, und den Wert als out-Variable bereitstellt. Wenn der Schlüssel nicht vorhanden ist, gibt sie false zurück und die out-Variable ist null.
JSValueObject obj = new JSValueObject() { { "2", 3}, { "hello", "world" }, { "x", 4 } };
if (obj.TryGetValue("hello", out JSValue value))
{
// value is "world"
}
if (obj.TryGetValue("no_such_key", out JSValue value2))
{
// this block will not be executed
}
// value2 is null
Übersicht
Hier sind einige Codebeispiele für den Einstieg (vorausgesetzt, es wurde ein #include "JSValue.h" verwendet)
JSValue twelve = 12; // creates a JSValue that holds an integer
JSValue str = "string"; // yep, this one is a String
// a few other types.
JSValue nul = nullptr;
JSValue boolean = false;
// Arrays can be initialized with JSValueArray.
JSValueArray array = JSValueArray{ "array ", "of", 4, " elements" };
assert(array.size() == 4);
JSValueArray emptyArray = JSValueArray{};
assert(emptyArray.size() == 0);
// JSValueArrays can be explicitly converted to JSValues, however
// like all JSValues they will be immutable. Accessing the contents
// via the AsArray() method will return a const JSValueArray.
JSValue array2 = std::move(array);
assert(array2.AsArray().size() == 4);
JSValue emptyArray2 = std::move(emptyArray);
assert(emptyArray2.AsArray().size() == 0);
// Maps from strings to JSValues are called objects. The
// JSValueObject type is how you make an empty map from strings
// to JSValues.
JSValueObject map = JSValueObject{};
map["something"] = 12;
map["another_something"] = map["something"].AsInt32() * 2;
// JSValueObjects may be initialized this way
JSValueObject map2 = JSValueObject
{
{ "something", 12 },
{ "another_something", 24 },
};
// Like JSValueArrays, JSValueObjects can also be explicitly
// converted to JSValues, and likewise they will be immutable.
// Accessing the contents via the AsObject() method will return
// a const JSValueObject.
JSValue map3 = std::move(map);
assert(map3.AsObject().size() == 2);
JSValue map4 = std::move(map2);
assert(map4.AsObject().size() == 2);
Laufzeit-Typüberprüfung und -konvertierungen
Während die meisten nicht unterstützten Operationen zu Kompilierungsfehlern führen, erfordern einige Operationen auf JSValues eine Laufzeitprüfung, ob der gespeicherte Typ mit der Operation kompatibel ist. Einige Operationen können Laufzeitausnahmen auslösen oder unerwartetes Verhalten aufweisen, wenn Typkonvertierungen fehlschlagen und Standardwerte zurückgegeben werden.
Weitere Beispiele werden dies hoffentlich verdeutlichen
JSValue dint = 42;
JSValue str = "foo";
JSValue thisDoesNotCompile = str + "something"; // compilation error
JSValue thisDoesNotCompile2 = str + dint; // compilation error
Explizite Typkonvertierungen können für einige der grundlegenden Typen angefordert werden
#ifdef max
#undef max
#endif
JSValue dint = 12345678;
JSValue doub = dint.AsDouble(); // doub will hold 12345678.0
JSValue str = dint.AsString(); // str == "12345678"
JSValue hugeInt = std::numeric_limits<int64_t>::max();
JSValue hugeDoub = hugeInt.AsDouble();
Iteration und Nachschlagen
Sie können über JSValueArrays iterieren, wie Sie es über jeden C++-Sequenzcontainer tun würden.
JSValueArray array = JSValueArray{ 2, 3, "foo" };
for (auto& val : array)
{
doSomethingWith(val);
}
Sie können über JSValueObjects wie über jede andere C++ std::map iterieren.
JSValueObject obj = JSValueObject{ { "2", 3}, { "hello", "world" }, { "x", 4 } };
for (auto& pair : obj)
{
// Key is pair.first, value is pair.second
processKey(pair.first);
processValue(pair.second);
}
Sie können ein Element anhand seines Schlüssels in einer dynamischen Karte mit der Methode find() finden, die einen Iterator zurückgibt
JSValueObject obj = JSValueObject{ { "2", 3}, { "hello", "world" }, { "x", 4 } };
auto pos = obj.find("hello");
// pos->first is "hello"
// pos->second is "world"
auto pos = obj.find("no_such_key");
// pos == obj.end()
Verwendung für JSON
Im Gegensatz zu folly::dynamic gibt es keine integrierten Mechanismen zum Parsen oder Erstellen von JSON-Strings direkt aus JSValues.
Leistung
JSValues können nützlich sein, um große und komplexe JS-Objekte in Ihrem nativen Code zu manipulieren, und bieten Ihnen wahlfreien Zugriff auf genau die Werte, die Sie benötigen. Beachten Sie jedoch, dass dies mit einem Leistungsaufwand verbunden ist, da das gesamte JS-Objekt in den JSValue geparst wird, bevor es an Ihren Code übergeben wird.
Der Leistungseinbruch durch die Verwendung von JSValue in Ihrem externen nativen Code ist zusätzlich zu dem Leistungseinbruch durch die interne Verwendung von folly::dynamic durch Microsoft.ReactNative zu verstehen. Daten werden über eine Hochleistungs-Serialisierungsschnittstelle aus Microsoft.ReactNative heraus marshallingt. Das Zurücklesen dieser Daten in ein JSValue bedeutet jedoch, dass Zeit und Speicher aufgewendet werden, um die ursprüngliche Objektstruktur vollständig neu zu erstellen.
Weitere Informationen finden Sie unter Marshalling von Daten.