Eu tenho uma PagedList<>
classe que implementa uma interface chamadaIPagedList<>
A classe não tem um construtor público, mas pode ser criada por meio de um método estático chamadoCreate
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);
}
Este método simplesmente invoca o construtor que é declarado private protected
.
Se o Create
método for invocado diretamente, o objeto retornado será umIPagedList<T>
Entretanto, quando o método é invocado por meio de reflexão, o tipo retornado é umPagedList<T>
Este é o código para reflexão
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!;
Esse comportamento é normal? Acontece porque estou usando dynamic
?
Quando o objeto criado é retornado ao chamador, que espera um IPagedList<T>
I obtém uma exceção que diz
System.InvalidCastException: Não é possível converter o objeto do tipo 'ApiResult
1[PagedList
1[ProgramResponse]]' para o tipo '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)
Estou incluindo o JsonConverter completo que desserializa o objeto IPagedList
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...]
}
}