抱歉,这是一个非常特殊的主题,因此许多人可能对此并不感兴趣。 :-(

但是,我需要做以下事情:

  • 我有一个应用程序,它提供对某种控制台窗口的日志记录(这是WPF窗口,由于应用程序要求,并且因为该应用程序即使在这里也需要显得浮华-我们的特殊客户要求这样做,每次见面时都要讨论)
  • 为了提供线程-不可知论的日志记录,我创建了一个接口(interface)/实现对“IGUIController” /“GUIController”

  • 到现在为止还挺好。没事的

    然而:
  • 我需要我自己的自定义跟踪侦听器(我称之为“GUITraceListener”),该侦听器使用IGUIController-接口(interface)将特定的日志消息写入该华而不实的WPF​​-窗口

  • 到目前为止,我的解决方案是在我的GUIController上拥有一个被破解的旧的skool代码气味单例-“当前”样式-属性(是的,我很as愧,我知道这很糟糕),我这样调用:
    GUIController.Current.Log(message);
    

    显然,这是不行的。

    因此,正确的方法是注入(inject)依赖关系(当然)。但是,当我这样做时,我收到了抱怨(运行时),因为我没有为GUITraceListener类提供一个带有0(零)自变量的构造函数。

    事实上,我在这里得到:
    EnterpriseLibraryContainer.ConfigureContainer(configurator,
    ConfigurationSourceFactory.Create());
    

    投诉是:

    未处理ArgumentException
    无法为GUITraceListener找到合适的0参数构造函数

    这真的很糟糕。我的意思是,Unity是企业库的一部分,为什么这些人没有简单地增加注入(inject)我的依赖项的可能性?

    澄清:

    我最后想要的是:
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="guiController"></param>
        public GUITraceListener(IGUIController guiController)
        {
            // Store the dependencies
            this.m_GUIController = guiController;
        }
    

    最佳答案

    Entlib 5确实具有执行此操作的能力。我猜您的侦听器类上有一个[ConfigurationElementType(typeof(CustomTraceListenerData)),对吗?

    Entlib 5设计为独立于容器。因此,我们不能依赖任何类型的 Autowiring 语义,因为每个容器的处理方式不同。因此,您需要告诉Entlib该调用哪个构造函数,以及应该注入(inject)哪些依赖项。这是通过您的配置数据类完成的。

    我拍了一个简单的例子。这是跟踪侦听器-没什么特别的:

    [ConfigurationElementType(typeof(GuiTraceListenerData))]
    public class GuiTraceListener : TraceListener
    {
        private readonly ILogFormatter formatter;
        private readonly IGuiController guiController;
    
        public GuiTraceListener()
            : this(string.Empty, null, null)
        {
        }
    
        public GuiTraceListener(string name)
            : this(name, null, null)
        {
        }
    
        public GuiTraceListener(string name, ILogFormatter formatter, IGuiController guiController) : base(name)
        {
            this.formatter = formatter;
            this.guiController = guiController;
        }
    
        public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id,
            object data)
        {
            if ((Filter == null) || Filter.ShouldTrace(eventCache, source, eventType, id, null, null, data, null))
            {
                if (data is LogEntry)
                {
                    if (formatter != null)
                    {
                        Write(formatter.Format(data as LogEntry));
                    }
                    else
                    {
                        base.TraceData(eventCache, source, eventType, id, data);
                    }
                }
                else
                {
                    base.TraceData(eventCache, source, eventType, id, data);
                }
            }
        }
    
        public override void Write(string message)
        {
            guiController.Log(message);
        }
    
        public override void WriteLine(string message)
        {
            guiController.Log(message);
        }
    }
    

    有趣的部分在GuiTraceListenerData类中:
    public class GuiTraceListenerData : TraceListenerData
    {
        private const string formatterNameProperty = "formatter";
    
        public GuiTraceListenerData()
            : this("unnamed", null, TraceOptions.None)
        {
        }
    
        public GuiTraceListenerData(string name)
            : this(name, null, TraceOptions.None)
        {
        }
    
        public GuiTraceListenerData(string name, string formatterName)
            : this(name, formatterName, TraceOptions.None)
        {
        }
    
        protected GuiTraceListenerData(string name, string formatterName, TraceOptions traceOutputOptions)
            : base(name, typeof (GuiTraceListener), traceOutputOptions, SourceLevels.All)
        {
            ListenerDataType = typeof (GuiTraceListenerData);
            Formatter = formatterName;
        }
    
        [ConfigurationProperty(formatterNameProperty, IsRequired = false)]
        [Reference(typeof(NameTypeConfigurationElementCollection<FormatterData, CustomFormatterData>), typeof(FormatterData))]
        public string Formatter
        {
            get { return (string) base[formatterNameProperty]; }
            set { base[formatterNameProperty] = value; }
        }
    
        protected override Expression<Func<TraceListener>> GetCreationExpression()
        {
            return () =>
                new GuiTraceListener(Name,
                    Container.ResolvedIfNotNull<ILogFormatter>(Formatter),
                    Container.Resolved<IGuiController>());
        }
    }
    

    特别是,请查看该GetCreationExpression方法。这告诉entlib,要创建由此配置new表示的对象,调用该构造函数,并解析格式程序(如果已指定)和IGuiController。

    然后,在测试应用程序中(为了快速起见,我使用Winforms)像这样初始化了我的容器和应用程序:
    static void Main()
    {
        var container = new UnityContainer()
            .AddNewExtension<EnterpriseLibraryCoreExtension>()
            .RegisterType<IGuiController, MessageBoxGuiController>();
    
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(container.Resolve<Form1>());
    }
    

    我的Form1类将LogWriter作为构造函数参数。

    关于Entlib 5如何构建的好处是,这样做时您几乎获得了自动配置工具的支持-无需编写单独的配置节点。您只需要运行时配置元素-只需使用config工具将DLL复制到同一目录中,然后将其拾取即可。

    无论如何,从这里开始就可以了。

    希望这可以帮助。如果您需要更多详细信息,请给我一行,然后我可以将整个工作项目发送给您。

    -克里斯

    10-06 13:09