C# 如何调用C中通过结构映射实例化的类的构造函数#

C# 如何调用C中通过结构映射实例化的类的构造函数#,c#,.net,class,structuremap,objectfactory,C#,.net,Class,Structuremap,Objectfactory,我有一个名为ILogger的接口,它基本上包含一些日志记录方法 Ilogger.cs public interface ILogger { void LogError(string message, Exception exception = null); void LogMessage(string message); void LogValidationError(UploadResult uploadResult); void LogValida

我有一个名为ILogger的接口,它基本上包含一些日志记录方法

Ilogger.cs

public interface ILogger
{   
    void LogError(string message, Exception exception = null);

    void LogMessage(string message);

    void LogValidationError(UploadResult uploadResult);

    void LogValidationError(ValidationResult validationResult);

    void LogProcessingError(string processingError);
}
我有一个LogHelper类,它实现了这个接口。LogHelper类是通过StructureMap类实例化的

ObjectFactory.Initialize(
    request =>
    {
        request.For<ILogger>().Singleton().Use<LogHelper>();

    });
当前,文件名被硬编码到LogHelper类的常量属性中,如
private string messageFilename=“logs\\UserCreationResult.log”

但是我希望每当LogHelper被实例化时,文件名都被动态发送。
我想拥有一个类属性,并在实例化该类时在构造函数中定义该属性。但是由于LogHelper类被实例化为
ObjectFactory.GetInstance()
。我无法调用可以在其中传递文件名的构造函数。

您将日志记录器作为一个单例使用,因此每次调用
ObjectFactory.GetInstance()时都不会创建实例,您只需始终获得对第一次使用时创建的同一个记录器实例的引用

如果要写入特定的目标,那么最好的解决方案是在
日志记录
方法中指定目标:

 void LogError(string message, 
               Exception exception = null,
               string destination = /*some adequate defualt value*/);

void LogMessage(string message,
                string destination = /*some adequate defualt value*/);
如果从预期的方法同时使用记录器,并因此设置不同的目标,则在记录器实例中创建具有特定目标的状态信息可能是危险的;你可以在不应该记录的地方记录东西


这提出了一个重要问题;由于您在应用程序(单例)中共享记录器,因此如果可能会以这种方式调用记录器,请确保其方法可以安全地并发调用。

您将记录器作为单例使用,因此您不会每次调用
ObjectFactory.GetInstance(),您只需始终获得对第一次使用时创建的同一个记录器实例的引用

如果要写入特定的目标,那么最好的解决方案是在
日志记录
方法中指定目标:

 void LogError(string message, 
               Exception exception = null,
               string destination = /*some adequate defualt value*/);

void LogMessage(string message,
                string destination = /*some adequate defualt value*/);
如果从预期的方法同时使用记录器,并因此设置不同的目标,则在记录器实例中创建具有特定目标的状态信息可能是危险的;你可以在不应该记录的地方记录东西


这提出了一个重要问题;因为您在应用程序(singleton)中共享记录器,所以如果有可能以这种方式调用记录器,请确保其方法可以安全地并发调用。

不幸的是,您这样做有点弄巧成拙。您的类只知道
ILogger
,而不知道
ILogger
的任何特定实现。这很好-这意味着实现可以写入文件、SQL表或任何内容

但是,如果您的类只知道
ILogger
,而不知道实现,那么您的类如何知道记录器需要文件路径?如果在
ILogger
中更改方法签名以包含文件路径,则会发生两种情况

  • 不可能有任何不写入文件的
    ILogger
    实现(除非它忽略文件路径,这将非常奇怪)
  • 现在,调用记录器的类必须知道文件路径。该类将从何处获取文件路径?它会存储在类中吗?在这种情况下,您将得到一个无法工作的类,除非它是在计算机上执行的程序集的一部分,在该计算机上它可以写入精确的文件路径
  • 相反,登录位置和方式的详细信息应该存在于
    ILogger
    实现中。这更接近于单一责任原则。调用
    ILogger
    的类不负责决定
    ILogger
    的工作方式。它不知道也不想知道。它说“在这里,拿着这个并记录它。”记录器实现负责其余的工作

    我建议完全取消静态的
    ObjectFactory
    ,使用容器解析和创建所有类,包括记录器和依赖它的类,但这太广泛了,没有什么帮助。(它已被弃用,因为它是一种糟糕的模式。它甚至不在最新版本的StructureMap中。)

    以上所有内容都是建议。在此之后,我将提供一个不太推荐的选项,但需要较少的更改,并使您的类不知道文件路径,因为请永远不要这样做。

    一种选择(折衷方案)可能是注册不同的
    ILogger
    命名实现。您可以将记录器类修改为如下所示:

    public class FileLogger : ILogger
    {
        private readonly string _filePath;
    
        public FileLogger(string filePath)
        {
            _filePath = filePath;
        }
    }
    
    var logger = ObjectFactory.GetNamedInstance<ILogger>("LoggerOne");
    
    现在,您可以创建该记录器类的多个实例,向每个实例传递不同的文件路径。这样,它就不是一个静态属性,它将您限制为只有一个文件路径

    然后您可以像这样注册您的实现

    ObjectFactory.Initialize(
        request =>
        {
            request.For<ILogger>().Singleton()
                .Use<FileLogger>(() => new FileLogger("some path")).Name = "LoggerOne";
    
            request.For<ILogger>().Singleton()
                 .Use<FileLogger>(() => new FileLogger("some other path")).Name = "LoggerTwo";
    
        });
    
    ObjectFactory.Initialize(
    请求=>
    {
    request.For().Singleton()
    .Use(()=>newfilelogger(“某些路径”)).Name=“LoggerOne”;
    request.For().Singleton()
    .Use(()=>newfilelogger(“其他路径”)).Name=“LoggerTwo”;
    });
    
    现在,您的类可以说出它想要哪个记录器,如下所示:

    public class FileLogger : ILogger
    {
        private readonly string _filePath;
    
        public FileLogger(string filePath)
        {
            _filePath = filePath;
        }
    }
    
    var logger = ObjectFactory.GetNamedInstance<ILogger>("LoggerOne");
    
    var logger=ObjectFactory.GetNamedInstance(“LoggerOne”);
    

    但请不要真的那样做。这超出了我在这里详细描述的范围,但是看一看依赖注入,这样你的类实际上只知道
    ILogger
    ,不知道或不关心它们得到的是哪个实现,也不告诉它如何完成它的工作。

    不幸的是,你这样做有点自欺欺人。哟