存在不同程序集时的部分/扩展类或接口

本文关键字:扩展 接口 程序集 存在 | 更新日期: 2023-09-27 17:58:19

我使用一个方法来处理异常-它在内部写入数据库,但在发布到web时,源代码将不包括写入数据库所需的连接字符串。相反,它应该写入日志文件。

是否可以在Foo.Private.dll不存在的情况下允许写入日志,但在存在时允许写入数据库?

//In Foo.Public.dll assembly
public class SimpleLogWriter
{
    public virtual void LogError(Exception ex)
    {
        //Write to log file.
    }
}

//In Foo.Private.dll assembly
public class ExtendedLogWriter : SimpleLogWriter
{
    public override void LogError(Exception ex)
    {
        //Write to database
    }
}

我曾考虑过让两个日志类实现共享接口(而不是扩展和重写),并创建一些工厂方法来渲染它,但不确定如何在不添加引用的情况下验证程序集的存在或使用其类型,在这种情况下,最终项目将具有循环引用。

存在不同程序集时的部分/扩展类或接口

这听起来像是.NET 4.0中提供的托管可扩展性框架(MEF)的潜在用例。

我可以想出几种方法来实现这一点。

紧密耦合

使用反射来检测DLL的存在。如果存在,请加载适当的类,并对它们进行额外调用。

要执行此操作,请使用Assembly.LoadFile、Assembly.GetType(字符串)和Activator.CreateInstance(类型)。将新实例强制转换为抽象的基本记录器类型/接口。

这或多或少就是你所描述的。不过,我不建议这样做,因为它不是很灵活,而且有很好的替代方案。

松散耦合

创建一个接口或抽象记录器类,并使用依赖注入(控制反转)将记录器注入到需要进行日志记录的组件中。如果您选择,您可以使用依赖项注入库来以松散耦合的方式指定您想要的实现。配置DI库以从额外的DLL(如果存在)加载依赖项。

Windsor有一个紧密耦合的日志记录接口(日志记录设施),您可以考虑第二种选择。

这两者之间也有一种光谱。

这是将记录器作为依赖项注入的要点(尽管在本例中我没有使用任何库):

using System;
using System.IO;
public interface ILogger
{
    void WriteDebug(string debug);
    void WriteInfo(string info);
    void WriteError(string error);
}
public class NullLogger : ILogger
{
    private static ILogger instance = new NullLogger();
    // This singleton pattern is just here for convenience.
    // We do this because pattern has you using null loggers constantly.
    // If you use dependency injection elsewhere,
    // try to avoid the temptation of implementing more singletons :)
    public static ILogger Instance
    {
        get { return instance; }
    }
    public void WriteDebug(string debug) { }
    public void WriteInfo(string info) { }
    public void WriteError(string error) { }
}
public class FileLogger : ILogger, IDisposable
{
    private StreamWriter fileWriter;
    public FileLogger(string filename)
    {
        this.fileWriter = File.CreateText(filename);
    }
    public void Dispose()
    {
        if (fileWriter != null)
            fileWriter.Dispose();
    }
    public void WriteDebug(string debug)
    {
        fileWriter.WriteLine("Debug - {0}", debug);
    }
    // WriteInfo, etc
}
public class SomeBusinessLogic
{
    private ILogger logger = NullLogger.Instance;
    public SomeBusinessLogic()
    {
    }
    public void DoSomething()
    {
        logger.WriteInfo("some info to put in the log");
    }
    public ILogger Logger
    {
        get { return logger; }
        set { logger = value; }
    }
}
public class Program
{
    static void Main(string[] args)
    {
        // You're free to use a dependency injection library for this,
        // or simply check for a DLL via reflections and load a logger from there
        using (var logger = new FileLogger("logfile.txt"))
        {
            var someBusinessLogic = new SomeBusinessLogic()
            {
                // The component won't know which logger it is using - it just uses it
                Logger = logger,
            };
            someBusinessLogic.DoSomething();
        }
    }
}

这听起来实际上只是如何创建日志编写器的问题。与其根据DLL是否存在来尝试这样做,不如允许类被实例化为整体配置的一部分。让用户(我指的是安装它的人)指定ExtendedLogWriter,如果他们想要,如果他们有Foo.Private.dll,否则指定SimpleLogWriter。有各种各样的IoC容器可以使这变得容易。

这可以通过使用控制反转来解决。

具有LogError(Exception)方法的接口IErrorLogger通过以下方式实现:

  • DbErrorLogger
  • 文件错误记录器

使用某些控制反转API(如Castle Windsor),您可以以不同的方式配置IErrorLogger组件,因为ASP.NET 4.0具有Web.debug.configWeb.release.config,允许配置一些Web应用程序以调试和发布到Web场景。

最终,当您将编译更改为发布时,FileErrorLogger将是IErrorLogger的实现。

通过以下链接了解更多信息:http://docs.castleproject.org/Windsor.MainPage.ashx