首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >根据泛型类型C#创建对象的工厂

根据泛型类型C#创建对象的工厂
EN

Stack Overflow用户
提问于 2009-07-17 18:05:19
回答 8查看 14.5K关注 0票数 8

例如,根据传递给Factory类的泛型类型实例化对象的最有效方法是什么:

代码语言:javascript
运行
复制
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();
    }
}

你会怎么做?哪个分支语句?等等。

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2009-07-17 20:55:30

我认为最好保持简单,也许是这样的:

代码语言:javascript
运行
复制
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不是很快,但是创建一个记录器可能不会成为瓶颈。希望看上去还好。

用法:

代码语言:javascript
运行
复制
// initialize somewhere
LoggerFactory.AddLoggerProvider<String, StringLogger>();
LoggerFactory.AddLoggerProvider<Exception, ExceptionLogger>();
// etc..

ILogger<string> stringLogger = LoggerFactory.CreateLogger<string>();

注意:每个ILogger<T>都需要一个Activator的无参数构造函数,但是添加方法中的new()泛型约束也确保了这一点。

票数 18
EN

Stack Overflow用户

发布于 2009-07-17 20:12:31

我想我会这样做:

代码语言:javascript
运行
复制
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),但正如您所看到的,它几乎没有程序逻辑。

票数 6
EN

Stack Overflow用户

发布于 2009-07-17 19:29:58

虽然我通常建议使用依赖注入框架,但是您可以使用反射实现一些东西,这些反射将搜索可用的类型,以找到实现适当ILogger接口的类型。

我建议您仔细考虑哪些程序集将包含这些记录器实现,以及希望该解决方案具有多大的可扩展性和防弹性。在可用的程序集和类型中执行运行时搜索并不便宜。但是,在这种类型的设计中允许扩展是一种简单的方法。它还避免了预先配置的问题--但是它只要求单个具体类型实现特定版本的ILogger<>接口--否则您必须解决一个不明确的情况。

您可能希望执行一些内部缓存,以避免对Create()的每个调用执行反射的开销。

下面是一些示例代码,您可以从这里开始。

代码语言:javascript
运行
复制
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>(); 
    }
}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1144835

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档