Что-то типа
void RegisterAs(Func??? register)
{
register<IService1, Service1>(); // <-- call func like this
register<IService2, Service2>(); // <-- or this
register<IService3, Service3>();
}
И я хочу назвать этот метод как
RegisterAs(services.AddScoped)
Или
RegisterAs(services.AddSingleton)
3 ответа
В C# нет такого типа, который позволил бы вам вызывать делегата с аргументами универсального типа, поэтому в общем случае это невозможно. Если бы в C# были типы более высокого типа, это было бы возможно, но я не думаю, что это произойдет в ближайшее время :(
Вместо двух параметров универсального типа вы можете разрешить вызывающей стороне передать Func<Type, Type, IServiceCollection>
:
void RegisterAs(Func<Type, Type, IServiceCollection> register)
{
register(typeof(IService1), typeof(Service1));
register(typeof(IService2), typeof(Service2));
register(typeof(IService3), typeof(Service3));
}
На callsite вы по-прежнему можете делать:
RegisterAs(services.AddScoped);
Поскольку это использует другая перегрузка AddScoped
, которая занимает 2 Type
с. а не 2 параметра универсального типа.
Что ж, можно передать Func<>
с параметрами типа. Эти параметры нельзя использовать в качестве универсальных. Вы можете использовать typeof()
и передать это как параметр.
Но если вы хотите иметь только переменное время жизни, вы можете сделать это двумя разными способами, в этом случае нет необходимости передавать Func<>. Просто передайте время жизни в качестве параметра (первые два примера):
var sc = new ServiceCollection();
// With generics types
void AddMe<T, T2>(ServiceLifetime lifetime)
{
sc.Add(ServiceDescriptor.Describe(typeof(T), typeof(T2), lifetime));
}
// Or like you have
void RegisterAs(ServiceLifetime lifetime)
{
sc.Add(ServiceDescriptor.Describe(typeof(IService1), typeof(Service1), lifetime));
sc.Add(ServiceDescriptor.Describe(typeof(IService2), typeof(Service2), lifetime));
sc.Add(ServiceDescriptor.Describe(typeof(IService3), typeof(Service3), lifetime));
}
// Via a passed Func - not my preferred solution
void RegisterAsWithFunc(Func<Type, Type, IServiceCollection> register)
{
register(typeof(IService1), typeof(Service1));
}
Звонок будет таким же простым, как
RegisterAs(ServiceLifetime.Scoped);
В отличие от переданного Func, вы не увидите большой разницы на первый взгляд:
RegisterAsWithFunc(sc.AddScoped);
Да. Например, все операторы LINQ принимают универсальные функции Func. Подпись Enumerable.Where это:
Where<TSource>(this IEnumerable<TSource>, Func<TSource,Boolean>)
Методы регистрации промежуточного программного обеспечения .NET Core Dependency Injection также принимают общие функции для фабричных методов, например один из AddScoped:
AddScoped<TService,TImplementation> (
this Microsoft.Extensions.DependencyInjection.IServiceCollection services,
Func<IServiceProvider,TImplementation> implementationFactory)
Вы можете использовать это для создания нового экземпляра службы с помощью настраиваемого фабричного метода.
Новые вопросы
c#
C # (произносится как «резкий») - это высокоуровневый, статически типизированный язык программирования с несколькими парадигмами, разработанный Microsoft. Код C # обычно нацелен на семейство инструментов и сред выполнения Microsoft .NET, включая, среди прочего, .NET Framework, .NET Core и Xamarin. Используйте этот тег для вопросов о коде, написанном на C # или в формальной спецификации C #.
RegisterAs
общим?IServiceCollection
расширенияvoid RegisterAs<T>(Func<T> f) where T: BaseInterface
.Func<TValue, TResult>
, если вы не используете возвращаемое значение? Вместо этого вы можете выбратьAction<T>
.