[C#]在Microsoft.Extensions.DependencyInjection中使用属性注入

背景

  • 有一些特殊需求,需要像StringBoot那样使用属性注入。(不推荐使用属性注入)

实现

  1. 设计一个属性注入注解: InjectAttribute
[AttributeUsage(AttributeTargets.Property)]
public class InjectAttribute : Attribute
{

}
  1. 设计属性注入服务接口: IResolvedService
public interface IResolvedService<TService> where TService : class
{
    TService Service { get; }
}
  1. 实现属性注入服务
internal class ServiceResolver<TService> : IResolvedService<TService> where TService : class
{
    private static readonly ConcurrentDictionary<Type, PropertyInfo[]> _propertyCache = new();

    public ServiceResolver(IServiceProvider serviceProvider)
    {
        Service = ResolveService(serviceProvider);
    }

    public TService Service { get; }

    private static void InjectProperties(IServiceProvider services, object instance)
    {
        ArgumentNullException.ThrowIfNull(instance);

        var properties = _propertyCache.GetOrAdd(instance.GetType(), type =>
            type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                .Where(prop => prop.CanWrite && Attribute.IsDefined(prop, typeof(InjectAttribute)))
                .ToArray());

        foreach (var property in properties)
        {
            var dependency = services.GetService(property.PropertyType)
                ?? throw new InvalidOperationException($"Failed to resolve dependency for property '{property.Name}' of type '{property.PropertyType.FullName}'.");
            property.SetValue(instance, dependency);
        }
    }

    private static TService ResolveService(IServiceProvider services)
    {
        var service = services.GetService(typeof(TService));

        if (service is not TService typedService)
        {
            throw new InvalidOperationException($"Unable to resolve service of type '{typeof(TService).FullName}'.");
        }

        InjectProperties(services, typedService);
        return typedService;
    }
}
  1. 在DI中注册服务
services.AddTransit(typeof(IResolvedService<>),typeof(ResolvedService<>));
  1. 定义属性注入
public class ExampleService
{
    [Inject] 
    DependencyService Dependency { get; set; }
}
  1. 使用服务
  • 使用构造注入
public class SomeViewModel
{
    private readonly ExampleService _exampleService;

    public SomeViewModel(IResolvedService<ExampleService> exampleService)
    {
       _exampleService = exampleService.Service;
    }
}
  • 使用ServiceProvider获取服务
IResolvedService resolver = serviceProvider.GetRequiredService<IResolvedService<ExampleService>();
ExampleService service = resolver.Service;

最后

spring官方也不推荐属性注入,微软没有支持这个也是正常的。这里给有需要的兄弟提供一下思路。

posted @ 2026-04-01 17:35  Echo_HR910  阅读(3)  评论(0)    收藏  举报