2014-02-06 87 views
1

儘管通過構造函數傳遞依賴關係的建議,但我發現無參數構造函數的開發成本,然後在所有內容上自動裝配所有屬性的開發成本要少得多,並且使得應用程序的開發和維護更容易。然而有時(例如在視圖模型上)我有一個屬性已註冊到容器,但我不想在構造時填充(例如選定的項綁定到容器)。Autofac PropertiesAutowired - 是否可以忽略一個或多個屬性?

有沒有什麼辦法告訴容器忽略某些屬性,當它自動裝配其餘的?

目前我只是重新標記在上激活事件一拉屬性屬性:

public static IRegistrationBuilder<TLimit, ScanningActivatorData, TRegistrationStyle> 
    PropertiesAutowiredExtended<TLimit, TRegistrationStyle>(
    this IRegistrationBuilder<TLimit, ScanningActivatorData, TRegistrationStyle> builder) 
{ 
    builder.ActivatorData.ConfigurationActions.Add(
     (type, innerBuilder) => 
     { 
      var parameter = Expression.Parameter(typeof(object)); 
      var cast = Expression.Convert(parameter, type); 
      var assignments = type.GetProperties() 
       .Where(candidate => candidate.HasAttribute<NotAutowiredAttribute>()) 
       .Select(property => new { Property = property, Expression = Expression.Property(cast, property) }) 
       .Select(data => Expression.Assign(data.Expression, Expression.Default(data.Property.PropertyType))) 
       .Cast<Expression>() 
       .ToArray(); 

      if (assignments.Any()) 
      { 
       var @action = Expression 
        .Lambda<Action<object>>(Expression.Block(assignments), parameter) 
        .Compile(); 

       innerBuilder.OnActivated(e => 
       { 
        e.Context.InjectUnsetProperties(e.Instance); 
        @action(e.Instance); 
       }); 
      } 
      else 
      { 
       innerBuilder.OnActivated(e => e.Context.InjectUnsetProperties(e.Instance)); 
      } 
     }); 

    return builder; 
} 

有沒有更好的方式來做到這一點?

回答

2

不確定這是否更好,但是您可以從另一面進行操作,只需通過WithProperty語法註冊所需的屬性即可。優點是Autofac不能解決不必要的服務。這裏有一個工作示例:

public class MyClass 
{ 
    public MyDependency MyDependency { get; set; } 
    public MyDependency MyExcludeDependency { get; set; } 
} 
public class MyDependency {} 

public class Program 
{ 
    public static void Main(string[] args) 
    { 
     var builder = new ContainerBuilder(); 
     builder.RegisterType<MyDependency>(); 
     builder.RegisterType<MyClass>().WithPropertiesAutowiredExcept("MyExcludeDependency"); 

     using (var container = builder.Build()) 
     { 
      var myClass = container.Resolve<MyClass>(); 

      Console.WriteLine(myClass.MyDependency == null); 
      Console.WriteLine(myClass.MyExcludeDependency == null); 
     } 
    } 
} 

public static class PropertiesAutowiredExtensions 
{ 
    // Extension that registers only needed properties 
    // Filters by property name for simplicity 
    public static IRegistrationBuilder<TLimit, TReflectionActivatorData, TRegistrationStyle> 
     WithPropertiesAutowiredExcept<TLimit, TReflectionActivatorData, TRegistrationStyle>(
     this IRegistrationBuilder<TLimit, TReflectionActivatorData, TRegistrationStyle> registrationBuilder, 
     params string[] propertiesNames) 
     where TReflectionActivatorData : ReflectionActivatorData 
    { 
     var type = ((IServiceWithType)registrationBuilder.RegistrationData.Services.Single()).ServiceType; 

     foreach (var property in type 
      .GetProperties(BindingFlags.Public | BindingFlags.Instance) 
      .Where(pi => pi.CanWrite && !propertiesNames.Contains(pi.Name))) 
     { 
      // There's no additional checks like in PropertiesAutowired for simplicity 
      // You can add them from Autofac.Core.Activators.Reflection.AutowiringPropertyInjector.InjectProperties 

      var localProperty = property; 
      registrationBuilder.WithProperty(
       new ResolvedParameter(
        (pi, c) => 
         { 
          PropertyInfo prop; 
          return pi.TryGetDeclaringProperty(out prop) && 
            prop.Name == localProperty.Name; 
         }, 
        (pi, c) => c.Resolve(localProperty.PropertyType))); 
     } 

     return registrationBuilder; 
    } 

    // From Autofac.Util.ReflectionExtensions 
    public static bool TryGetDeclaringProperty(this ParameterInfo pi, out PropertyInfo prop) 
    { 
     var mi = pi.Member as MethodInfo; 
     if (mi != null && mi.IsSpecialName && mi.Name.StartsWith("set_", StringComparison.Ordinal) 
      && mi.DeclaringType != null) 
     { 
      prop = mi.DeclaringType.GetProperty(mi.Name.Substring(4)); 
      return true; 
     } 

     prop = null; 
     return false; 
    } 
} 
+0

謝謝,我想你是對的,我應該從另一端開始,並推出自己的autowirer,而不是捏造出來的容器已經完成的工作。 – briantyler

+0

@TheMouthofaCow權利。甚至可以爲項目做出貢獻並在Autofac.Core.Activators.Reflection.AutowiringPropertyInjector.InjectProperties中引入一個謂詞,這可以給出一個很好的擴展點。 –

+0

是的,如果我能在週末度過一些時間,我會非常高興。 – briantyler

相關問題