У меня есть Type
из некоторых AssemblyContext
(код плагина). Я знаю, что та же сборка также загружается в контексте по умолчанию. Я хочу иметь метод, который возвращает объект типа из соответствующей сборки в контексте по умолчанию.
Вот мой код
public object GetService(Type serviceType, IServiceProvider provider) {
try
{
// If same context
var defaultService = provider.GetService(serviceType);
if (defaultService != null)
{
return defaultService;
}
}
catch (InvalidOperationException ex) { }
/// The <see cref="serviceType"/> might come from an external assembly.
/// Try to find a matching type within the assemblies loaded with the
/// <see cref="Provider"/>'s <see cref="AssemblyLoadContext"/>.
var providerContext =
AssemblyLoadContext.GetLoadContext(provider.GetType().Assembly);
var resolvedAssembly = FindBestMatch(providerContext.Assemblies.ToList(),
serviceType.Assembly.GetName());
Type resolvedType = null;
if (serviceType.IsGenericType)
{
resolvedType = resolvedAssembly
.GetType(serviceType.GetGenericTypeDefinition().FullName, throwOnError: true)
.MakeGenericType(serviceType.GetGenericArguments());
}
else
{
resolvedType = resolvedAssembly.GetType(serviceType.FullName, true);
}
var resolvedService = provider.GetService(resolvedType);
return ImpromptuInterface.Impromptu.DynamicActLike(resolvedService, serviceType);
}
FindBestMatch просто выглядит для сборки, хотя список -
Assembly FindBestMatch(IReadOnlyCollection<Assembly> choices, AssemblyName hint)
{
if (choices == null) throw new ArgumentNullException(nameof(choices));
if (hint == null) throw new ArgumentNullException(nameof(hint));
return choices.FirstOrDefault(choice => choice.GetName() == hint)
?? choices.FirstOrDefault(choice => choice.GetName().FullName == hint.FullName)
?? choices.FirstOrDefault(choice => choice.GetName().Name == hint.Name);
}
Теперь он отлично работает для не-дженериков. Для таких обобщений, как ILogger<T>
, он создает объект типа Logger<T>
, но выдает RunTimeBinderException при попытке вызвать методы для этих объектов. Например, для регистратора сообщение об исключении гласит: «« Регистратор »не содержит определения для« LogDebug »».
Итак:
- что здесь происходит?
- есть ли лучший способ добиться этого?