Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/311.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#_Reflection_Factory_Factory Pattern - Fatal编程技术网

C# 基于字符串实例化对象的最佳方法

C# 基于字符串实例化对象的最佳方法,c#,reflection,factory,factory-pattern,C#,Reflection,Factory,Factory Pattern,我想讨论一下基于输入字符串实例化对象的最佳方法(在C#中)。让我解释一下。 假设我有一个基类: public abstract class BaseCar { public asbtract int GetEngineID(); //Other stuff... } 然后我有几个此类的实现,比如: public class SportCar : BaseCar { public override int GetEngine() { //Speci

我想讨论一下基于输入字符串实例化对象的最佳方法(在C#中)。让我解释一下。 假设我有一个基类:

public abstract class BaseCar 
{
    public asbtract int GetEngineID();
    //Other stuff...
}
然后我有几个此类的实现,比如:

public class SportCar : BaseCar
{
    public override int GetEngine()
    { 
      //Specific implementation
    }

}

public class OtherCar: BaseCar
{
    public override int GetEngine()
    { 
      //Specific implementation
    }

}
等等

我想做的是创建一个静态CarFactory类,它有一个
CreateCar
方法,该方法接受
string
作为参数,并返回一个
BaseCar
实例,具体取决于您给出的字符串。该字符串将是子类的名称

例如,如果我调用
CarFactory.CreateCar('SportCar')
它应该返回一个SportCar实例

我知道我可以使用一个简单的switch语句来检查请求了哪辆车,并基于此创建一个新实例,但我不喜欢这种方法,原因有两个:

  • 我计划有很多子类,硬编码每个
    案例都不会太容易维护
  • 我计划实现一个日化过程,为我创建的对象提供一些初始值(使用反射),所以混合硬编码和反射对我来说似乎不是一个好主意
我考虑的是使用System.Reflection中的
Assembly.CreateInstance
来创建指定类的实例,但由于这是我第一次处理这个问题,我不知道是否有更好的方法来实现这一点。这是一种有效的方法吗


考虑到输入字符串将来自XML文件,是否有更简单的方法?也许我的问题已经在某个.NET程序集中得到了处理,而我却缺少了它。

以下是我的想法。一个泛型工厂类,它自动注册作为给定类型的子类的所有类型,并允许您通过它们的名称实例化它们。这在某种程度上与注释中@Achiles链接的方法有关,只是没有与类型相关的初始化功能

不需要维护所有类型的枚举/开关组合。它还应该易于扩展,以处理建议的基于反射的初始化

static class StringFactory<T> where T : class
{
    static private Dictionary<string, Type> s_dKnownTypes = new Dictionary<string, Type>();

    static StringFactory()
    {
        RegisterAll();
    }

    static private void RegisterAll()
    {
        var baseType = typeof(T);
        foreach (var domainAssembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            foreach (var type in domainAssembly.GetTypes()
                .Where(t => t.IsSubclassOf(baseType)))
            {
                s_dKnownTypes.Add(type.Name, type);
            }
        }
    }

    static public T Create(string _sTypeName)
    {
        Type knownType;
        if (s_dKnownTypes.TryGetValue(_sTypeName, out knownType))
        {
            return (T)Activator.CreateInstance(knownType);
        }

        throw new KeyNotFoundException();
    }
}
静态类StringFactory,其中T:class
{
静态私有字典s_dKnownTypes=新字典();
静态StringFactory()
{
registeral();
}
静态私有void RegisterAll()
{
var baseType=类型(T);
foreach(AppDomain.CurrentDomain.GetAssemblys()中的var domainAssembly)
{
foreach(domainAssembly.GetTypes()中的变量类型)
.其中(t=>t.IsSubclassOf(baseType)))
{
添加(type.Name,type);
}
}
}
静态公共文件不能创建(字符串_sTypeName)
{
类型知识型;
if(s_dKnownTypes.TryGetValue(_sTypeName,out knownType))
{
return(T)Activator.CreateInstance(knownType);
}
抛出新的KeyNotFoundException();
}
}
假设问题的类别存在,您将实例化一辆特定的汽车,如下所示:

var car = StringFactory<BaseCar>.Create("SportsCar");
DoSomethingWith(car.EngineID());
var-car=StringFactory.Create(“跑车”);
DoSomethingWith(car.EngineID());

既然你的问题是为了讨论最好的方法,请考虑这只是其中的一个。我没有在生产环境中使用过这种方法,完全有可能它是针对您的特定情况的错误方法。不过,它足以说明一般原理,应该为进一步讨论提供一个起点。

这里的相同查询(针对java)。。应该提供一些提示:感谢您的想法,实际上我认为注册所有可用类型一次,然后使用数据结构映射它们是一种很好的方法,而不是每次重新请求实例时都在程序集中查找指定的类型。