Почему JavaScriptSerializer возвращает неправильный ответ при вызове из JScript.NET?

В ASP.NET/C#:

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Web.Script.Serialization" %>
<%
JavaScriptSerializer jss = new JavaScriptSerializer();
string[] fruits = new string[3] {"apple","banana","crunchberries"};
string output = jss.Serialize(fruits);
%>
<html>
fruits=<%=output%>
</html>

возвращается fruits=["apple","banana","crunchberries"]

В ASP.NET/VB.NET:

<%@ Page Language="VB" %>
<%@ Import Namespace="System.Web.Script.Serialization" %>
<%
dim jss as new JavaScriptSerializer()
dim fruits  = new String(2) {"apple","banana","crunchberries"}
dim output as string =  jss.Serialize(fruits)
 %>
<html>
fruits=<%=output%>
</html>

возвращается fruits=["apple","banana","crunchberries"]

Но в ASP.NET/JScript.NET:

<%@ Page Language="JScript" %>
<%@ Import Namespace="System.Web.Script.Serialization" %>
<%
var jss:JavaScriptSerializer = new JavaScriptSerializer;
var fruits = ["apple","banana","crunchberries"];
var output = jss.Serialize(fruits);
%>
<html>
fruits=<%=output%>
</html>

возвращается fruits=["0","1","2"]

Это кажется полностью сломанным. Это можно исправить, явно объявив тип данных fruit, что превращает это в "собственный массив":

<%@ Page Language="JScript" %>
<%@ Import Namespace="System.Web.Script.Serialization" %>
<%
var jss:JavaScriptSerializer = new JavaScriptSerializer;
var fruits:String = ["apple","banana","crunchberries"];
var output = jss.Serialize(fruits);
%>
<html>
fruits=<%=output%>
</html>

возвращается fruits=["apple","banana","crunchberries"]

Я не понимаю, почему тип является обязательным для получения правильной сериализации. (var fruits = ["apple","banana","crunchberries",5] может быть плохим кодом, но это допустимо как в Javascript, так и в Jscript.) Предполагается, что массивы JScript медленнее, чем собственные массивы, но они все еще должны работать, верно?

2 ответа

Решение

Я обвинял JavaScriptSerializer, но проблема, похоже, связана с беспорядком раздвоения личности, который имеет JScript с типами данных "JScript" против типов данных ".NET Framework".

Во-первых, реабилитация JavaScriptSerializer. Он может обрабатывать смешанные типы данных в массиве, как показано в следующем примере VB:

dim a as string = "apple"
dim b as int32 = 5
dim c as double = 22.22222
dim fruits(2) as  Object
fruits(0) = a
fruits(1) = b
fruits(2) = c
dim output as string =  jss.Serialize(fruits)

Это возвращает ["apple",5,22.22222], что правильно. Порт этого кода (в комплекте с явными объявлениями типов для скаляров и создания массива объектов Framework длины 3) в JScript также дает правильный ответ:

var a:String="apple";
var b:Int32=5;
var c:Double=22.2;
var fruits:Object = new Object[3];
fruits[0]=a;
fruits[1]=b;
fruits[2]=c;
var output = jss.Serialize(fruits);

Но никто не пишет Javascript таким образом. Вместо этого вы бы написали стек гибкого типа, используя:

var fruits = new Array();
fruits.push("apple");
fruits.push(5);
fruits.push(22.22222);

который использует объекты массива JScript "expando". Это нормально, если вы остаетесь в контексте JScript, но вызов чего-либо в фреймворке вызывает проблемы.

Основная проблема здесь - отказ JScript преобразовать объекты JScript в массивы и объекты Framework (CLR) по мере необходимости. В обсуждении объекта-массива JScript 10.0 есть своего рода предупреждение. ("Следовательно, при аннотировании типов параметров и возвращаемых типов CLS-совместимых методов обязательно используйте тип данных System.Array вместо объекта Array".) Ух, я уверен, что рад, что компилятор JScript ищет для меня!

Трудно сказать что-нибудь хорошее о JScript.NET здесь. Похоже на то, что возникает проблема с наличием среды с двумя слегка различающимися типами массивов и двумя слегка различающимися типами объектов. Как ни странно, Visual C# 2010 только что представил "динамические" типы и объекты Expando, которые могут выполняться в новой среде выполнения "DLR", поэтому, вероятно, теперь можно было бы сделать менее изворотливую версию JScript.

Похоже, проблема вывода типа - то есть, возможно, интерпретируется JScript.NET ["apple","banana","crunchberries"] как массив целых

Вы можете попробовать создать функцию, которая принимает object и звони, что вместо JavaScriptSerializer.Serialize, Проверьте передаваемое значение, чтобы увидеть, что это такое.

Другие вопросы по тегам