#c# #generics #reflection
#c# #общие #отражение
Вопрос:
У меня есть список общих типов, определенных следующим образом:
class Registrations
{
private readonly List<MetaRegistration> _registrations = new List<MetaRegistration>();
private abstract class MetaRegistration
{
}
private class Registration<T> : MetaRegistration
{
public async Task<T> Resolve(string value)
{
return await ...
}
}
}
И я хотел бы запустить метод в одном из Registration<T>
экземпляров.
Я могу легко сделать это так, если я знаю тип во время компиляции:
public async Task<T> Resolve<T>(string value)
{
var registration = _registrations.Cast<Registration<T>>()
.First(r => r.GetType().GenericTypeArguments[0] == typeof(T));
var model = await registration.Resolve(value);
return model;
}
Но как бы я обошелся без этого, если я не знаю T?
Прямо сейчас, вот как я решил проблему, используя отражение, где я знаю тип, но только во время выполнения:
public async Task<object?> Resolve(Type type, string value)
{
foreach (var metaRegistration in _registrations)
{
Type t = metaRegistration.GetType();
if (!t.IsGenericType || t.GetGenericTypeDefinition() != typeof(Registration<>) ||
t.GenericTypeArguments[0] != type) continue;
var methodInfo = metaRegistration.GetType().GetMethod("Resolve");
var task = (Task) methodInfo?.Invoke(metaRegistration, new object?[] {value})!;
await task;
return task.GetType().GetProperty("Result")?.GetValue(task);
}
return null;
}
Однако я бы предпочел избегать совместного отражения, и такое ощущение, что я делаю что-то неправильно.
Есть ли какой-либо другой способ сделать это?
Комментарии:
1. Вы не собираетесь избегать размышлений или моральных эквивалентов. Когда вы используете общие типы, ожидается, что вы будете знать типы во время компиляции (либо с явными типами, либо, если ваш собственный код является универсальным, используя параметры вашего типа)
2. Это также часто указывает на то, что generics на самом деле был неправильным инструментом для использования здесь, и, возможно, вместо этого вам нужен был, например, интерфейс
3. Вы можете использовать
switch/case
с сопоставлением с образцом и всеми перечисленными типами. Автоматического преобразования изType
T
того, что вы хотите, нет, где-то вы либо решаете во время компиляции, какой тип использовать, либо переходите к отражению.4. @Damien_The_Unbeliever Я бы хотел использовать интерфейс, я работаю с объектами ядра EF, и они часто заменяются при обновлении базы данных, удаляя интерфейсы / атрибуты, которые, возможно, уже размещены. :/
5. Действительно, вам не нужно писать все это отражение вручную, поскольку вы уже успешно используете
dynamic
…