我有一个PagedList<>
实现接口的类,称为IPagedList<>
该类没有公共构造函数,但可以通过静态方法创建Create
public static IPagedList<T> Create(IEnumerable<T> items, int pageNumber, int pageSize, int totalItems) {
Ensure.That.IsNotNull(items);
Ensure.That.IsNotZeroOrNegative(pageNumber);
Ensure.That.IsNotZeroOrNegative(pageSize);
var totalItemCount = totalItems;
return new PagedList<T>(items, pageNumber, pageSize, totalItemCount);
}
此方法只是调用声明的构造函数private protected
。
如果Create
直接调用该方法,则返回的对象是IPagedList<T>
然而,当通过反射调用该方法时,返回的类型是PagedList<T>
这是反射的代码
var typeToCall = typeof(PagedList<>).MakeGenericType(targetType);
MethodInfo createMethod = typeToCall.GetMethod("Create")!;
dynamic result = createMethod.Invoke(null, new object[] { value, pageNumber, pageSize, totalItems })!;
return (IPagedList)result!;
这种行为正常吗?是不是因为我使用了 才发生这种情况dynamic
?
当创建的对象返回给调用者时,它期望IPagedList<T>
我得到一个异常,说
System.InvalidCastException:无法将类型“ApiResult
1[PagedList
1[ProgramResponse]]”的对象转换为类型“ApiResult1[IPagedList
1[ProgramResponse]]”。
at System.Text.Json.ThrowHelper.ThrowInvalidCastException_DeserializeUnableToAssignValue(Type typeOfValue, Type declaredType)
at System.Text.Json.JsonSerializer.<UnboxOnRead>g__ThrowUnableToCastValue|50_0[T](Object value)
at System.Text.Json.JsonSerializer.UnboxOnRead[T](Object value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 utf8Json, JsonTypeInfo`1 jsonTypeInfo, Nullable`1 actualByteCount)
at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 json, JsonTypeInfo`1 jsonTypeInfo)
我包括反序列化 IPagedList 对象的完整 JsonConverter
internal class NativePagedListConverter : JsonConverter<IPagedList> {
public override bool CanConvert(Type typeToConvert) {
return typeToConvert.IsPagedList();
}
public override IPagedList? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
if (reader.TokenType != JsonTokenType.StartObject) {
throw new JsonException();
}
int pageNumber = 0;
int pageSize = 0;
int totalItems = 0;
dynamic value = default!;
var targetType = typeToConvert.GetGenericArguments()[0]!;
while (reader.Read()) {
if (reader.TokenType == JsonTokenType.EndObject) {
break;
}
if (reader.TokenType != JsonTokenType.PropertyName) {
throw new JsonException();
}
var propertyName = reader.GetString() ?? string.Empty;
reader.Read();
if (propertyName.Equals(nameof(pageNumber), StringComparison.OrdinalIgnoreCase)) {
pageNumber = reader.GetInt32();
}
else if (propertyName.Equals(nameof(pageSize), StringComparison.OrdinalIgnoreCase)) {
pageSize = reader.GetInt32();
}
else if (propertyName.Equals(nameof(totalItems), StringComparison.OrdinalIgnoreCase)) {
totalItems = reader.GetInt32();
}
else if (propertyName.Equals("Items", StringComparison.OrdinalIgnoreCase)) {
var itemsType = typeof(IEnumerable<>).MakeGenericType(targetType);
value = JsonSerializer.Deserialize(ref reader, itemsType, options)!;
}
}
var typeToCall = typeof(PagedList<>).MakeGenericType(targetType);
MethodInfo createMethod = typeToCall.GetMethod("Create")!;
dynamic result = createMethod.Invoke(null, new object[] { value, pageNumber, pageSize, totalItems })!;
return (IPagedList)result!;
}
public override void Write(Utf8JsonWriter writer, IPagedList value, JsonSerializerOptions options) {
[...omitted as not interesting for the question...]
}
}
ApiResult<T>
虽然您还没有分享或IPagedList<T>
或的实现,但这看起来是需要工厂转换器模式PagedList<T>
的情况:假设你的类型看起来像这样:
然后,您可以定义以下工厂转换器和内部通用转换器,如下所示:
现在假设您有一些项目类别,例如如下:
您将能够按如下方式序列化和反序列化
PagedList<MyItem>
或IPagedList<MyItem>
:笔记:
在内部转换器中,不需要手动写入和读取每个属性,而是可以更轻松地将要序列化的类型映射到某个内部DTO,然后对 DTO 进行序列化和反序列化。
在本机 AOT应用中使用源生成时,工厂转换器模式可能无法工作。(例如,不能保证在这样的应用中工作。)相反,需要为所有类型手动创建内部转换器,例如:
Type.MakeGenericType()
MethodInfo.MakeGenericMethod()
PagedListConverter<T>
T
演示小提琴在这里。