tl; dr - я десериализую объекты (например, экземпляр «Animal
») без отражения и хочу получить его фактический тип, чтобы я мог создавать связанные объекты ( например, «Result<Animal>
»). Я также пишу код фреймворка, поэтому не могу просто явно привести к типу. Есть ли разумный способ сделать это?
Я имею дело с сериализацией и хочу иметь возможность использовать полученный тип при создании связанных объектов: например, если я десериализую в "* 1009" * ", Я хочу создать экземпляр контейнера, например," Result<Animal>
". Для этого мне нужен тип (T
), а не экземпляр типа (Type
).
Я обнаружил, что могу заранее создать список статически типизированных вспомогательных классов (Helper<Animal>
, Helper<Person>
, ...), найдите нужный через «deserializedAnimal.runtimeType
», затем вызовите, скажем, «buildResult(deserializedAnimal)
». Это, будучи специально созданным для Animal
s, знает, что имеет дело с Animal
и может явно создать Result<Animal>.
. Я также нашел способ сделать это в общем, добавив метод к помощник с общим аргументом закрытия c. Помощник связывает параметр типа замыкания с типом stati c перед его вызовом. В результате замыкание получает экземпляр, который имеет соответствующий тип среды выполнения и тип c, плюс его параметр типа правильно привязан и может использоваться для создания экземпляров других типов (например, Result<T>
с T
, привязанным к Animal
).
Все это кажется немного запутанным, но я убежден, что мне нужно что-то подобное, чтобы восстановить параметр типа после сериализации (опять же, чтобы я мог передать результат обобщенному c и поверьте, что параметр типа привязан к фактическому типу stati c, а не, скажем, dynamic
).
Кажется ли что-нибудь из этого шатким? Не хватает чего-нибудь попроще?
Пример кода:
class Identifiable<T> {
Id<T> id;
}
class Id<T> {}
class Person extends Identifiable<Person> {}
class Animal extends Identifiable<Animal> {}
class Resolver<T extends Identifiable> {
void resolve(dynamic arg, void Function<V extends Identifiable>(dynamic) func) {
func<T>(arg);
}
}
final dynamic resolvers = {
Id<Person>().runtimeType: Resolver<Person>(),
Id<Animal>().runtimeType: Resolver<Animal>()
};
void reveal<T extends Identifiable>(Id<T> id) {
print("Static: ${Id<T>().runtimeType}");
print("Dynamic: ${id.runtimeType}\n");
}
void resolve(dynamic arg, void Function<V extends Identifiable>(dynamic) func) {
resolvers[arg.runtimeType].resolve(arg, func);
}
main() {
dynamic lst = [];
lst.add(Id<Person>());
lst.add(Id<Animal>());
/*
Static: Id<Identifiable<dynamic>>
Dynamic: Id<Person>
*/
reveal(lst[0]);
/*
Static: Id<Person>
Dynamic: Id<Person>
*/
resolve(lst[0], <V extends Identifiable>(arg){
reveal<V>(arg);
});
}