我正在用 C# 开发 ActivityPub 实现,有时链接是像 url 链接一样的“字符串”,有时链接是具有 Link 子类型的对象。 (链接:实体)
我想知道如果一组特定条件为真(只需将一个字符串写入编写器),是否有可能使用 System.Text.Json 将 Link 对象序列化为字符串,并将整个默认对象写入如果条件不成立,请联系作者。
我尝试遵循此解决方案:How to use default serialization in a custom System.Text.Json JsonConverter?,它仍然适用于代码小提琴,但不适用于我的实现,我不太确定为什么。
有谁知道我如何调试这个,或者有更好的方法来确保
Link : Entity
对象有时可以序列化为字符串?
我收到以下错误:
(在这种情况下,我什至尝试将获取的默认 ctor 添加到 修改选项)
无论如何,它表示没有为 Link 类映射数据。 我还尝试将
JsonSerializeable
属性直接添加到 Link 类中。
错误:
类型“ActivityPub.Types.Link”的元数据未提供给序列化器。使用的序列化程序方法不支持基于反射创建序列化相关类型元数据。如果使用源生成,请确保传递给序列化器的所有根类型都已用“JsonSerializedAttribute”指示,以及可能以多态方式序列化的任何类型
我的基础代码库:https://github.com/Meep-Tech/ActivityHub.Net/tree/collapse_links_during_serialization
测试代码:
static void Main(string[] args) {
Settings.DefaultContext = new Link("ActivityPub.Net.Testing");
var testObject = new Object {
Type = "Test",
At = new Link("/terry") {
Rels = new string[] {
"test",
"test2"
}
},
Attribution = "/meep",
Audience = new Link("/all") {
Rel = "test"
}
};
string json = testObject
.Serialize();
System.IO.File.WriteAllLines(
"test.json",
new[] { json }
);
Object @object = json.DeSerializeEntity<Object>();
System.IO.File.WriteAllLines(
"test1.json",
new[] { @object.ToString() }
);
}
public DictionaryEnumConverterInner(JsonSerializerOptions options)
{
// For performance, use the existing converter if available.
_valueConverter = (JsonConverter<TValue>)options
.GetConverter(typeof(TValue));
// Cache the key and value types.
_keyType = typeof(TKey);
_valueType = typeof(TValue);
}
但是,由于以下几个原因,这已被证明是有问题的:
object
的声明
类型序列化多态值时,
GetConverter()
返回非功能转换器。
编译时序列化器源生成时,返回的转换器可能无法工作。
DefaultConverter<T>
如下:
public abstract class DefaultConverterFactory<T> : JsonConverterFactory
{
class DefaultConverter : JsonConverter<T>
{
readonly JsonSerializerOptions modifiedOptions;
readonly DefaultConverterFactory<T> factory;
public DefaultConverter(JsonSerializerOptions options, DefaultConverterFactory<T> factory)
{
this.factory = factory;
this.modifiedOptions = options.CopyAndRemoveConverter(factory.GetType());
}
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) => factory.Write(writer, value, modifiedOptions);
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => factory.Read(ref reader, typeToConvert, modifiedOptions);
}
protected virtual T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions modifiedOptions)
=> (T)JsonSerializer.Deserialize(ref reader, typeToConvert, modifiedOptions);
protected virtual void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions modifiedOptions)
=> JsonSerializer.Serialize(writer, value, modifiedOptions);
public override bool CanConvert(Type typeToConvert) => typeof(T) == typeToConvert;
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) => new DefaultConverter(options, this);
}
public static class JsonSerializerExtensions
{
public static JsonSerializerOptions CopyAndRemoveConverter(this JsonSerializerOptions options, Type converterType)
{
var copy = new JsonSerializerOptions(options);
for (var i = copy.Converters.Count - 1; i >= 0; i--)
if (copy.Converters[i].GetType() == converterType)
copy.Converters.RemoveAt(i);
return copy;
}
}
然后,在从 DefaultConverterFactory<T>
派生的任何类(例如this one)中,从
JsonConverter<T> defaultConverter
和
Read()
中删除最后一个参数
Write()
,您的代码现在应该可以工作了。(顺便说一句,您似乎错误地使用了
[JsonSerializable(typeof(Link))]
Link
,但是根据docs,它应该应用于
JsonSerializerContext
的某些子类你的模型——不是模型本身。)