当不同的装配存在时的部分/扩展类或接口

时间:2011-06-01 06:19:58

标签: c# reflection partial class-extensions

我使用一种方法来处理异常 - 在内部写入数据库,但是当发布到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
    }
}

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

4 个答案:

答案 0 :(得分:1)

我可以想到几种方法可以实现这一目标。

紧密耦合

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

为此,请使用Assembly.LoadFileAssembly.GetType(string)Activator.CreateInstance(type)。将新实例转换为抽象基本记录器类型/接口。

这或多或少是你所描述的。我不建议这样做,因为它不是很灵活,而且有很好的选择。

松散耦合

创建一个接口或抽象记录器类,并使用Dependency Injection (Inversion of Control)将记录器注入需要记录的组件中。如果选择,可以使用依赖注入库以松散耦合的方式指定所需的实现。配置DI库以从您的额外DLL(如果存在)加载依赖项。

Castle.Windsor有一个松散耦合的日志记录界面(logging facility),您可以查看第二个选项。

这些之间也有一种光谱。

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

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();
        }
    }
}

答案 1 :(得分:1)

这听起来像是{4.0}中可用的Managed Extensibility Framework(MEF)的潜在用例。

答案 2 :(得分:0)

这听起来真的只是你如何创建日志编写器。而不是尝试根据DLL是否存在来执行此操作,只需允许将类实例化为整体配置的一部分。让用户(我指的是安装它的人)如果他们想要的话指定ExtendedLogWriter,如果他们有Foo.Private.dll,则指定SimpleLogWriter。有各种各样的IoC容器可以使这很容易。

答案 3 :(得分:0)

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

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

  • DbErrorLogger
  • FileErrorLogger

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

在一天结束时,当您将编译更改为发布时,FileErrorLogger将是IErrorLogger实现。

点击以下链接了解详情:http://docs.castleproject.org/Windsor.MainPage.ashx