例如,根据传递给Factory类的泛型类型实例化对象的最有效方法是什么:
public class LoggerFactory
{
public static ILogger<T> Create<T>()
{
// Switch Statement?
// Generic Dictionary?
// EX.: if "T" is of type "string": return (ILogger<T>)new StringLogger();
}
}
你会怎么做?哪个分支语句?等等。
发布于 2009-07-17 12:55:30
我认为最好保持简单,也许是这样的:
public static class LoggerFactory
{
static readonly Dictionary<Type, Type> loggers = new Dictionary<Type, Type>();
public static void AddLoggerProvider<T, TLogger>() where TLogger : ILogger<T>, new()
{
loggers.Add(typeof(T), typeof(TLogger));
}
public static ILogger<T> CreateLogger<T>()
{
//implement some error checking here
Type tLogger = loggers[typeof(T)];
ILogger<T> logger = (ILogger<T>) Activator.CreateInstance(tLogger);
return logger;
}
}
您只需为您想要支持的每一种类型调用AddLoggerProvider
,可以在运行时进行扩展,它确保您明确地将接口的实现添加到库中,而不是某个对象,因为Activator
不是很快,但是创建一个记录器可能不会成为瓶颈。希望看上去还好。
用法:
// initialize somewhere
LoggerFactory.AddLoggerProvider<String, StringLogger>();
LoggerFactory.AddLoggerProvider<Exception, ExceptionLogger>();
// etc..
ILogger<string> stringLogger = LoggerFactory.CreateLogger<string>();
注意:每个ILogger<T>
都需要一个Activator
的无参数构造函数,但是添加方法中的new()
泛型约束也确保了这一点。
发布于 2009-07-17 12:12:31
我想我会这样做:
public class LoggerFactory<T>
{
private static Dictionary<Type, Func<ILogger<T>>> LoggerMap =
new Dictionary<Type, Func<ILogger<T>>>
{
{ typeof(string),
() => new StringILogger() as ILogger<T> },
{ typeof(StringWriter),
() => new StringWriterILogger() as ILogger<T> }
};
public static ILogger<T> CreateLogger()
{
return LoggerMap[typeof(T)]();
}
}
您需要付出一些可读性的代价(所有这些尖括号,sheesh),但正如您所看到的,它几乎没有程序逻辑。
发布于 2009-07-17 11:29:58
虽然我通常建议使用依赖注入框架,但是您可以使用反射实现一些东西,这些反射将搜索可用的类型,以找到实现适当ILogger接口的类型。
我建议您仔细考虑哪些程序集将包含这些记录器实现,以及希望该解决方案具有多大的可扩展性和防弹性。在可用的程序集和类型中执行运行时搜索并不便宜。但是,在这种类型的设计中允许扩展是一种简单的方法。它还避免了预先配置的问题--但是它只要求单个具体类型实现特定版本的ILogger<>接口--否则您必须解决一个不明确的情况。
您可能希望执行一些内部缓存,以避免对Create()的每个调用执行反射的开销。
下面是一些示例代码,您可以从这里开始。
using System;
using System.Linq;
using System.Reflection;
public interface ILogger<T> { /*... */}
public class IntLogger : ILogger<int> { }
public class StringLogger : ILogger<string> { }
public class DateTimeLogger : ILogger<DateTime> { }
public class LoggerFactory
{
public static ILogger<T> Create<T>()
{
// look within the current assembly for matching implementation
// this could be extended to search across all loaded assemblies
// relatively easily - at the expense of performance
// also, you probably want to cache these results...
var loggerType = Assembly.GetExecutingAssembly()
.GetTypes()
// find implementations of ILogger<T> that match on T
.Where(t => typeof(ILogger<T>).IsAssignableFrom(t))
// throw an exception if more than one handler found,
// could be revised to be more friendly, or make a choice
// amongst multiple available options...
.Single();
/* if you don't have LINQ, and need C# 2.0 compatibility, you can use this:
Type loggerType;
Type[] allTypes = Assembly.GetExecutingAssembly().GetTypes();
foreach( var type in allTypes )
{
if( typeof(ILogger<T>).IsAssignableFrom(type) && loggerType == null )
loggerType = type;
else
throw new ApplicationException( "Multiple types handle ILogger<" + typeof(T).Name + ">" );
}
*/
MethodInfo ctor = loggerType.GetConstructor( Type.EmptyTypes );
if (ctor != null)
return ctor.Invoke( null ) as ILogger<T>;
// couldn't find an implementation
throw new ArgumentException(
"No mplementation of ILogger<{0}>" + typeof( T ) );
}
}
// some very basic tests to validate the approach...
public static class TypeDispatch
{
public static void Main( string[] args )
{
var intLogger = LoggerFactory.Create<int>();
var stringLogger = LoggerFactory.Create<string>();
var dateTimeLogger = LoggerFactory.Create<DateTime>();
// no logger for this type; throws exception...
var notFoundLogger = LoggerFactory.Create<double>();
}
}
https://stackoverflow.com/questions/1144835
复制相似问题