gpt4 book ai didi

javascript - 我可以使用 Json.NET 将对象序列化为 JavaScript 构造函数调用吗?

转载 作者:太空宇宙 更新时间:2023-11-03 22:36:39 25 4
gpt4 key购买 nike

我需要将大型数据集写入网页(使用服务器端呈现),页面中运行的 JavaScript 组件将使用这些数据集。此数据由数据网格组件和图表组件的对象数组组成(因此每个数组元素都是一个数据网格行)。

出于性能原因,我想使用 JavaScript 对象构造函数而不是对象字面量(有针对使用构造函数的对象的 JIT 编译器优化,并且由于省略了属性名称,它们在线使用的空间更少)。我也可以在本地使用 Date 构造函数。

这是我现在的做法:

<script type="text/javascript">

function WeeklySalesRow( weekName, date, totalSales, profit, loss, turnover, deltaSalesPercentage, etc )
{
this.weekName = weekName;
this.date = date;
this.totalSales = totalSales;
this.profit = profit;
this.loss = loss;
// etc
}

var weeklySalesData = [
@{
Boolean first = true;
foreach( WeeklySalesRow row in this.Model.WeeklySalesData ) {
if( !first ) this.WriteLine( "," ); first = false;
this.Write( "new WeeklySalesRow( \"{0}\", new Date({1}), {2}, {3}, {4}, etc )", row.WeekName, row.Date.ToUnixTimestamp(), row.TotalSales, row.Profit, row.Loss, row.Turnover, etc );
}
}
];

function onDomContentLoaded( e ) {

var chartCompoennt = ...
chartComponent.loadData( weeklySalesData );
}

</script>

像这样呈现:

// [...]

var weeklySalesData = [
new WeeklySalesRow( "2018W1", new Date(1514764800), 1100, 200, 900, 50, 0.56, etc ),
new WeeklySalesRow( "2018W2", new Date(1515369600), 1200, 100, 800, 45, 0.80, etc ),
new WeeklySalesRow( "2018W3", new Date(1515974400), 1300, 50, 700, 65, 0.12, etc ),
new WeeklySalesRow( "2018W4", new Date(1516752000), 1400, 25, 600, 80, 0.45, etc ),
new WeeklySalesRow( "2018W5", new Date(1517443200), 1500, 12, 500, 90, 0.123, etc ),
// etc...
];

// [...]

哪个更简洁:

var weeklySalesData = [
{ weekName: "2018W1", date: "2018-01-01", totalSales: 1100, profit: 200, loss: 900, turnover: 50, deltaSalesPercentage: 0.56, etc },
{ weekName: "2018W2", date: "2018-01-08", totalSales: 1200, profit: 100, loss: 800, turnover: 50, deltaSalesPercentage: 0.56, etc },
{ weekName: "2018W3", date: "2018-01-17", totalSales: 1300, profit: 50, loss: 700, turnover: 50, deltaSalesPercentage: 0.56, etc },
{ weekName: "2018W4", date: "2018-01-23", totalSales: 1400, profit: 25, loss: 600, turnover: 50, deltaSalesPercentage: 0.56, etc },
{ weekName: "2018W5", date: "2018-02-01", totalSales: 1500, profit: 12, loss: 500, turnover: 50, deltaSalesPercentage: 0.56, etc },
];

我知道能够直接解析 JSON 的运行时组件(例如 fetchXMLHttpRequest)能够减轻使用对象字面量带来的某些性能危害符号(例如,解析器检查数组并发现所有对象文字共享同一组属性名称,因此可以在运行时为它们定义一个内部隐藏基类)——但这种优化不适用于这种情况,因为数据正在呈现到 SSR 网页中,我知道即使是最近的性能基准也没有为“所有数组元素看起来相似”的场景显示任何解析器或编译器优化。

有没有办法让 Json.NET 自动为我做这件事,使用反射自动生成 JavaScript 构造函数和 JavaScript 构造函数调用?

最佳答案

无法完全自动执行此操作,但您可以使用 custom JsonConverter 来完成那叫 JsonWriter.WriteStartConstructor(string name) 及以后 JsonWriter.WriteEndCOnstructor() .参见 When using a JsonWriter, what's the purpose of WriteStartConstructor? 了解详情。通过使用 .Net 反射或 serializer.ContractResolver 返回的 Json.NET 缓存元数据,可以使自定义转换器通用。 ,但如果是,则需要一些方法来确定构造函数参数顺序。

例如,说你的类型 WeeklySalesData看起来像下面这样:

public class WeeklySalesData
{
string weekName;
DateTime date;
decimal totalSales;

// If WeeklySalesData had multiple constructors, you could mark the one to use as follows:
// [JsonConstructor]
public WeeklySalesData(string weekName, DateTime date, decimal totalSales)
{
this.weekName = weekName;
this.date = date;
this.totalSales = totalSales;
}

public string WeekName { get { return weekName; } }

public DateTime Date { get { return date; } }

public decimal TotalSales { get { return totalSales; } }
}

请注意,它有一个参数化构造函数,Json.NET 将使用该构造函数在反序列化期间构造类型。要使用构造函数格式序列化此类类型,首先引入以下转换器:

public class ConstructorConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(T) == objectType;
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var contract = serializer.ContractResolver.ResolveContract(value.GetType()) as JsonObjectContract;
if (contract == null)
throw new JsonSerializationException(string.Format("Type {0} does not correspond to a JSON object.", value.GetType()));
// Possibly check whether JsonObjectAttribute is applied, and use JsonObjectAttribute.Title if present.
writer.WriteStartConstructor(value.GetType().Name);
foreach (var provider in contract.GetConstructorParameterValueProviders())
{
serializer.Serialize(writer, provider.GetValue(value));
}
writer.WriteEndConstructor();
}
}

public static partial class JsonExtensions
{
internal static IEnumerable<IValueProvider> GetConstructorParameterValueProviders(this JsonObjectContract contract)
{
return contract.CreatorParameters.Select(p => contract.GetConstructorParameterValueProvider(p)).ToArray();
}

internal static IValueProvider GetConstructorParameterValueProvider(this JsonObjectContract contract, JsonProperty parameter)
{
if (parameter.ValueProvider != null)
return parameter.ValueProvider;
var property = contract.Properties.GetClosestMatchProperty(parameter.PropertyName);
var provider = property == null ? null : property.ValueProvider;
if (provider == null)
throw new JsonSerializationException(string.Format("Cannot get IValueProvider for {0}", parameter));
return provider;
}
}

然后使用以下转换器序列化:

var data = new WeeklySalesData("2018W1", new DateTime(2019, 2, 15, 0, 0, 0, DateTimeKind.Utc), 1100);
var settings = new JsonSerializerSettings
{
Converters = { new JavaScriptDateTimeConverter(), new ConstructorConverter<WeeklySalesData>() },
};

var json = JsonConvert.SerializeObject(new [] { data }, Formatting.Indented, settings);

结果是:

[
new WeeklySalesData(
"2018W1",
new Date(
1550188800000
),
1100.0
)
]

注意事项:

演示 fiddle here .

关于javascript - 我可以使用 Json.NET 将对象序列化为 JavaScript 构造函数调用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54759586/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com