C# 如何调用C中通过结构映射实例化的类的构造函数#
我有一个名为ILogger的接口,它基本上包含一些日志记录方法 Ilogger.csC# 如何调用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
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
,不知道或不关心它们得到的是哪个实现,也不告诉它如何完成它的工作。不幸的是,你这样做有点自欺欺人。哟