Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 工厂根据通用类型C创建对象#_C#_Generics_Interface_Factory - Fatal编程技术网

C# 工厂根据通用类型C创建对象#

C# 工厂根据通用类型C创建对象#,c#,generics,interface,factory,C#,Generics,Interface,Factory,根据传递给工厂类的泛型类型实例化对象的最有效方法是什么,例如: public class LoggerFactory { public static ILogger<T> Create<T>() { // Switch Statement? // Generic Dictionary? // EX.: if "T" is of type "string": return (ILogger<T>)n

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

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();
    }
}
公共类日志工厂
{
公共静态ILogger创建()
{
//开关语句?
//通用词典?
//例如:如果“T”是“string”类型:返回(ILogger)new StringLogger();
}
}

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

取决于您打算处理多少类型。如果它很小(小于10),我建议使用switch语句,因为它读起来既快又干净。如果您想要更多,您可能需要一个查找表(哈希映射、字典等)或一些基于反射的系统。

switch语句与Dictionary-对于性能来说并不重要,因为开关是编译到字典中的。因此,这实际上是一个可读性和灵活性的问题。开关更易于阅读,另一方面,字典可以在运行时扩展。

,您可以考虑使用依赖注入框架。您可以使用因子将返回的泛型类型对其进行配置,并在配置中进行映射

Hrm。。。根据给定的运行时系统支持的内容,您实际上可以尝试在这方面更聪明一点。实际上,如果可以的话,我会尽量避免在代码中使用任何条件语句,特别是在多态和动态绑定代码中。这里有一个泛型类,为什么不使用它呢

例如,在Java中,您可以特别利用已有的静态方法来执行以下操作:

public class LoggerFactory<T>
{
    public static ILogger<T> CreateLogger(Class<? extends SomeUsefulClass> aClass);
    {
        // where getLogger() is a class method SomeUsefulClass and its subclasses
        // and has a return value of Logger<aClass>.
        return aClass.getLogger();

        // Or perhaps you meant something like the below, which is also valid.
        // it passes the generic type to the specific class' getLogger() method
        // for correct instantiation. However, be careful; you don't want to get
        // in the habit of using generics as variables. There's a reason they're
        // two different things.

        // return aClass.getLogger(T);
    }
}
public static void main(String[] args)
{
    Logger = LoggerFactory.createLogger(subclassOfUsefulClass.class);
    // And off you go!
}
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)]();
    }
}
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;
    }
}

这避免了使用任何条件,而且更加灵活:任何属于某个有用类的子类(或者实现logger接口)的类都可以返回正确类型的logger实例

尽管我通常会建议使用依赖注入框架,但您可以使用反射实现一些东西,在可用类型中搜索实现适当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>(); 
    }
}
使用系统;
使用System.Linq;
运用系统反思;
公共接口ILogger{/*…*/}
公共类IntLogger:ILogger{}
公共类StringLogger:ILogger{}
公共类DateTimeLogger:ILogger{}
公营伐木厂
{
公共静态ILogger创建()
{
//在当前程序集中查找匹配的实现
//这可以扩展到搜索所有加载的程序集
//相对容易-以牺牲性能为代价
//另外,您可能希望缓存这些结果。。。
var loggerType=Assembly.getExecutionGassembly()
.GetTypes()
//查找在T上匹配的ILogger实现
.Where(t=>typeof(ILogger).IsAssignableFrom(t))
//如果找到多个处理程序,则引发异常,
//可以修改为更友好,或者做出选择
//在多个可用选项中。。。
.Single();
/*如果您没有LINQ,并且需要C#2.0兼容性,则可以使用以下方法:
类型loggerType;
类型[]allTypes=Assembly.getExecutionGassembly().GetTypes();
foreach(所有类型中的变量类型)
{
if(typeof(ILogger).IsAssignableFrom(type)&&loggerType==null)
loggerType=类型;
其他的
抛出新的ApplicationException(“多类型句柄ILogger”);
}
*/
MethodInfo-ctor=loggerType.GetConstructor(Type.EmptyTypes);
如果(ctor!=null)
将ctor.Invoke(null)作为ILogger返回;
//找不到实现
抛出新的ArgumentException(
“不执行ILogger”+类型(T));
}
}
//一些非常基本的测试来验证该方法。。。
公共静态类类型分派
{
公共静态void Main(字符串[]args)
{
var intLogger=LoggerFactory.Create();
var stringLogger=LoggerFactory.Create();
var dateTimeLogger=LoggerFactory.Create();
//此类型没有记录器;引发异常。。。
var notFoundLogger=LoggerFactory.Create();
}
}

我想我应该这样做:

public class LoggerFactory<T>
{
    public static ILogger<T> CreateLogger(Class<? extends SomeUsefulClass> aClass);
    {
        // where getLogger() is a class method SomeUsefulClass and its subclasses
        // and has a return value of Logger<aClass>.
        return aClass.getLogger();

        // Or perhaps you meant something like the below, which is also valid.
        // it passes the generic type to the specific class' getLogger() method
        // for correct instantiation. However, be careful; you don't want to get
        // in the habit of using generics as variables. There's a reason they're
        // two different things.

        // return aClass.getLogger(T);
    }
}
public static void main(String[] args)
{
    Logger = LoggerFactory.createLogger(subclassOfUsefulClass.class);
    // And off you go!
}
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)]();
    }
}
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;
    }
}
公共类日志工厂
{
专用静态字典LoggerMap=
新词典
{
{typeof(字符串),
()=>新的StringILogger()作为ILogger},
{打字机,
()=>新的StringWriterLogger()作为ILogger}
};
公共静态ILogger CreateLogger()
{
返回LoggerMap[typeof(T)]();
}
}
你付出了一定的可读性代价(所有这些尖括号,嘘),但正如你所看到的那样,它只产生了很少的程序逻辑。

1)我总是惊讶于人们对日志记录的复杂性。对我来说似乎总是太过分了。如果log4net是开源的,我建议你去看看,事实上,你也可以使用它

2) 就我个人而言,我尽可能避免类型检查——这违背了泛型的观点。只要使用.ToString()方法,就可以了。

I thi