【问题标题】:UnityContainer.BuildUp() - Can I make it inject new instances into properties only if these are null?UnityContainer.BuildUp() - 只有当它们为空时,我才能让它注入新实例到属性中吗?
【发布时间】:2011-08-19 10:45:32
【问题描述】:

我正在反序列化这样一个类

class AClass{
    [Dependency]
    AnotherClass Property{ get; set; }
}

当我然后 BuildUp() 对象时,我希望 Unity 仅在属性为 null 时创建 AnotherClass 的新实例,否则只需对其执行 BuildUp。 有没有简单的方法来实现这一点?

编辑:我正在用 wpf 做 mvvm。这些类是视图模型,我对它们进行序列化,因为我想在运行之间保留一些属性,并且它们也有一些我希望统一注入的依赖项。因此,在反序列化之后,嵌套模型已经设置了属性,所以我不希望统一用新实例覆盖它,但我仍然希望它在其上调用 InjectionMethods 并在程序第一次运行时正常解析它并且嵌套模型为空。

【问题讨论】:

  • 你能再具体一点吗?该属性已设置的原因是什么?
  • @Steven 我希望现在我想要做的事情更清楚了。

标签: c# unity-container ioc-container property-injection


【解决方案1】:

我最终编写了一个统一扩展。 我找不到太多关于如何做到这一点的文档,所以我不太确定结果。 它似乎有效,但我有这种感觉,我可能写了一些可怕的东西.. 无论如何这里是代码,欢迎改进:

public class RecursiveBuildUpContainerExtension : UnityContainerExtension {
        protected override void Initialize(){
            Context.Strategies.Add( new RecursiveBuildUpBuilderStrategy( Context.Container ), UnityBuildStage.PreCreation );
        }
    }

    public class RecursiveBuildUpBuilderStrategy : BuilderStrategy {
        readonly IUnityContainer container;
        public RecursiveBuildUpBuilderStrategy( IUnityContainer container ) {
            this.container = container;
        }

        public override void PreBuildUp( IBuilderContext context ) {

            if( context.Existing == null ) return;

            foreach( var prop in context.Existing.GetType( ).GetProperties( ) ) {

                if( ContainsType<DependencyAttribute>( prop.GetCustomAttributes( true ) ) ) {

                    if( prop.GetValue( context.Existing, null ) == null ) {
                        var value = container.Resolve( prop.PropertyType );
                        prop.GetSetMethod( ).Invoke( context.Existing, new[] { value } );
                    }
                    else {
                        var value = container.BuildUp( prop.PropertyType, prop.GetValue( context.Existing, null ) );
                        prop.GetSetMethod( ).Invoke( context.Existing, new[] { value } );
                    }
                }
            }

            foreach (var method in context.Existing.GetType().GetMethods() ){
                if( ContainsType<InjectionMethodAttribute>( method.GetCustomAttributes( true ))){
                    var argsInfo = method.GetParameters( );
                    var args = new object[argsInfo.Length];

                    for( int i = 0; i < argsInfo.Length; i++ ) {
                        args[i] = container.Resolve( argsInfo[i].ParameterType );
                    }

                    method.Invoke( context.Existing, args );
                }
            }

            context.BuildComplete = true;
        }

        private static bool ContainsType<T>( IEnumerable<object> objects ){
            foreach (var o in objects){
                if( o is T ) return true;
            }
            return false;
        }

    }

【讨论】:

【解决方案2】:

您可以编写自己的BuildUp 方法,如下所示:

public static void BuildUpButSkipInitializedProperties(
    this UnityContainer container, object instance)
{
    var registeredTypes = (
        from registration in container.Registrations
        select registration.RegisteredType)
        .ToArray();

    var injectableProperties =
        from property in instance.GetType().GetProperties()
        where property.GetGetMethod() != null
        where property.GetSetMethod() != null
        where property.GetValue(instance, null) == null
        where registeredTypes.Contains(property.PropertyType)
        select property;

    foreach (var property in injectableProperties)
    {
        object value = container.Resolve(property.PropertyType);
        property.SetValue(instance, value);
    }
}

用法:

var instance = new AClass();

container.BuildUpButSkipInitializedProperties(instance);

我没有测试甚至编译这段代码,但它应该可以解决问题。请注意,由于它每次都迭代所有 Registrations 并使用反射注入所有属性,所以它可能不是禁食的东西 ;-)

【讨论】:

  • 这还不错,但是如果嵌套对象的级别超过两级,它将不起作用。我知道这不在我最初的问题中,所以无论如何感谢您的回答!你有我的 +1。
【解决方案3】:

有简单的方法吗?没有。

您需要编辑生成的 il,检测已经存在的对象...可以做到,但绝非简单。

【讨论】:

  • hmm.. 我不知道为什么我需要编辑 il.. 顺便说一句,我的班级是什么??
  • 容器本身动态生成IL来创建创建和解析对象的函数。这很复杂,但却是一场巨大的完美胜利。要获得您想要的行为,您需要生成不同的 IL。或者回到反思。无论哪种情况,它都是对容器本身的低级黑客攻击。
  • 是否有任何关于其工作原理的资源?我很难找到任何东西..我知道我可以阅读源代码,但解释会更好:)
猜你喜欢
  • 2013-12-05
  • 2019-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-20
  • 1970-01-01
相关资源
最近更新 更多