C# 是否可以从接受字符串的工厂方法实例化泛型类型?

C# 是否可以从接受字符串的工厂方法实例化泛型类型?,c#,generics,factory,instantiation,C#,Generics,Factory,Instantiation,我正在编写一个由导入程序和处理器组成的应用程序。导入程序将获取一个类型并实例化该类型的列表。处理器需要获取返回的列表 例如,我想调用Importer.GetObjects(),让它返回一个列表。然后将列表传递给我的组织处理者 类似地,我想调用Importer.GetObjects()并让它返回一个列表。然后将列表传递给我的地址处理器 我想把导入器和*处理器的创建放到工厂中。我已经删除了所有代码,并在下面生成了一个未受污染的示例。我的尝试没有成功,可能是因为我不完全理解诸如差异之类的话题 clas

我正在编写一个由导入程序和处理器组成的应用程序。导入程序将获取一个类型并实例化该类型的
列表
。处理器需要获取返回的列表

例如,我想调用
Importer.GetObjects()
,让它返回一个
列表。然后将列表传递给我的组织处理者

类似地,我想调用
Importer.GetObjects()
并让它返回一个
列表。然后将列表传递给我的地址处理器

我想把
导入器
和*处理器的创建放到工厂中。我已经删除了所有代码,并在下面生成了一个未受污染的示例。我的尝试没有成功,可能是因为我不完全理解诸如差异之类的话题

class Program
{
    static void Main(string[] args)
    {
        //What I am currently doing
        Importer<Organisation> importer = new Importer<Organisation>();
        List<Organisation> list = importer.GetObjects();
        OrganisationProcessor processor = new OrganisationProcessor();
        processor.Process(list);


        //***What I want to do*** 
        string name = "Organisation";  //Passed in from external source
        var importer = Factory.GetImporter(name);  //returns Importer<Organisation>
        var processor = Factory.GetProcessor(name); //returns OrganisationProcessor
        processor.Process(importer.GetObjects()); //.Process takes List<Organisation>
    }
}

public class Importer<T>
{
    public List<T> GetObjects()
    {
        return new List<T>();
    }
}


public class OrganisationProcessor
{
    public void Process(List<Organisation> objects)
    {
        //Do something
    }
}

public class AddressProcessor
{
    public void Process(List<Address> objects)
    {
        //Do something
    }
}

public class Organisation { }

public class Address { }
类程序
{
静态void Main(字符串[]参数)
{
//我现在在做什么
进口商=新进口商();
List=importer.GetObjects();
OrganizationProcessor处理器=新的OrganizationProcessor();
处理程序(列表);
//***我想做什么***
string name=“organization”;//从外部源传入
var importer=Factory.GetImporter(名称);//返回导入器
var processor=Factory.GetProcessor(name);//返回OrganizationProcessor
processor.Process(importer.GetObjects());//.Process获取列表
}
}
公营进口商
{
公共列表GetObjects()
{
返回新列表();
}
}
公共类组织处理器
{
公共作废处理(列出对象)
{
//做点什么
}
}
公共类地址处理器
{
公共作废处理(列出对象)
{
//做点什么
}
}
公共阶级组织{}
公共类地址{}

在您的工厂内获得。。。Methodes可以使用。此方法可以通过附加参数的assamby name和type name创建类的实例。

在您的工厂中,获取。。。Methodes可以使用。此方法可以通过附加参数的assamby name和type name创建类的实例。

GetImporter
GetProcessor
的返回类型必须是
object
。无法让这些方法使用字符串中的运行时信息并返回编译时已知类型的对象

您的样本必须如下所示:

string name = "Organisation";  //Passed in from external source
dynamic importer = Factory.GetImporter(name);  //returns Importer<Organisation>
dynamic processor = Factory.GetProcessor(name); //returns OrganisationProcessor
processor.Process(importer.GetObjects()); //.Process takes List<Organisation>
请注意,传入的字符串名称必须是包括命名空间在内的类型的全名,并且仅限于与这些方法位于同一程序集中的类型(组织、地址)。如果要在其他程序集中使用类型,则必须使用,但用于生成处理器类型名称的字符串连接将不起作用


我可能会对处理器类型使用自定义属性,然后使用自定义属性查找程序集中的所有类型,而不是使用简单的字符串连接来生成上面的类型名称。上述方案很脆弱,如果重命名某些类型,则很容易破坏。
GetImporter
GetProcessor
的返回类型必须是
object
。无法让这些方法使用字符串中的运行时信息并返回编译时已知类型的对象

您的样本必须如下所示:

string name = "Organisation";  //Passed in from external source
dynamic importer = Factory.GetImporter(name);  //returns Importer<Organisation>
dynamic processor = Factory.GetProcessor(name); //returns OrganisationProcessor
processor.Process(importer.GetObjects()); //.Process takes List<Organisation>
请注意,传入的字符串名称必须是包括命名空间在内的类型的全名,并且仅限于与这些方法位于同一程序集中的类型(组织、地址)。如果要在其他程序集中使用类型,则必须使用,但用于生成处理器类型名称的字符串连接将不起作用


我可能会对处理器类型使用自定义属性,然后使用自定义属性查找程序集中的所有类型,而不是使用简单的字符串连接来生成上面的类型名称。上述方案很脆弱,如果重命名某些类型,很容易破坏。

是的,这是可能的。假设您的类在同一个程序集中,下面的代码没有进行太多优化,但可以解决问题:

public static class Factory
{
    public static object GetImporter(string name)
    {
        var assembly = Assembly.GetExecutingAssembly();

        var type = assembly.GetTypes().Single(t => t.Name.Equals(name));
        var importType = typeof (Importer<>).MakeGenericType(type);

        return Activator.CreateInstance(importType);

    }

    public static object GetProcessor(string name)
    {
        var assembly = Assembly.GetExecutingAssembly();
        var type = assembly.GetTypes()
               .Single(t => t.Name.Equals(string.Format("{0}Processor", name)));

        return Activator.CreateInstance(type);
    }
}

是的,有可能。假设您的类在同一个程序集中,下面的代码没有进行太多优化,但可以解决问题:

public static class Factory
{
    public static object GetImporter(string name)
    {
        var assembly = Assembly.GetExecutingAssembly();

        var type = assembly.GetTypes().Single(t => t.Name.Equals(name));
        var importType = typeof (Importer<>).MakeGenericType(type);

        return Activator.CreateInstance(importType);

    }

    public static object GetProcessor(string name)
    {
        var assembly = Assembly.GetExecutingAssembly();
        var type = assembly.GetTypes()
               .Single(t => t.Name.Equals(string.Format("{0}Processor", name)));

        return Activator.CreateInstance(type);
    }
}

这应该可以做到,注意你最初的意图并没有改变,这甚至让我感到惊讶。还要注意的是,您必须在Factory中为文本类型添加名称空间。使用LINQ查找类型更灵活,但在一行中输入带有名称空间的类型路径更具可读性。我在没有名称空间的项目上执行了这个示例,效果很好

void Main()
{
    string name = "Organisation";  //Passed in from external source
    var importer = Factory.GetImporter(name);  //returns Importer<Organisation>
    var processor = Factory.GetProcessor(name); //returns OrganisationProcessor
    processor.Process(importer.GetObjects()); //.Process takes List<Organisation>
    Console.WriteLine (importer.GetObjects().GetType());
}

public static class Factory
{
    public static Importer GetImporter(string name)
    {           
            //add namespace to name here
        var desiredType = Type.GetType(name);

        return new Importer(desiredType);
    }
    public static Processor GetProcessor(string name)
    {
            //add namespace to name here
        var desiredType = Type.GetType(name+"Processor");

        return (Processor)Activator.CreateInstance(desiredType);
    }
}

public class Importer 
{
    Type _typeOfEntities;

    public Importer(Type typeOfEntities)
    {
        _typeOfEntities = typeOfEntities;
    }
    public IList GetObjects()
    {
        Type generic = typeof(List<>);

        Type constructed = generic.MakeGenericType(new Type[] {_typeOfEntities});

        return (IList)Activator.CreateInstance(constructed);
    }
}
public interface Processor
{
    void Process(IList objects);
}

public class OrganisationProcessor : Processor
{
    public void Process(IList objects)
    {
        var desiredTypedObject = objects as List<Organisation>;
        if(desiredTypedObject != null)
        ProcessImp(desiredTypedObject);
    }
    private void ProcessImp(List<Organisation> objects)
    {
        Console.WriteLine ("processing Organisation");
    }
}

public class AddressProcessor
{
    public void Process(List<Address> objects)
    {
        //Do something by analogy
    }
}

public class Organisation { }

public class Address { }
void Main()
{
string name=“organization”;//从外部源传入
var importer=Factory.GetImporter(名称);//返回导入器
var processor=Factory.GetProcessor(name);//返回OrganizationProcessor
processor.Process(importer.GetObjects());//.Process获取列表
Console.WriteLine(importer.GetObjects().GetType());
}
公共静态类工厂
{
公共静态导入器GetImporter(字符串名称)
{           
//在此处为名称添加名称空间
var desiredType=Type.GetType(名称);
返回新进口商(所需类型);
}
公共静态处理器GetProcessor(字符串名称)
{
//在此处为名称添加名称空间
var desiredType=Type.GetType(名称+“处理器”);
返回(处理器)Activator.CreateInstance(desiredType);
}
}
公营进口商
{
类型_实体类型;
公共进口商(实体类型)
{
_实体类型=实体类型;
}
公共IList GetObjects()
{
类型generic=typeof(列表);
类型constructed=generic.MakeGenericType(新类型[]{u typeOfEnt
void Main()
{
    string name = "Organisation";  //Passed in from external source
    var importer = Factory.GetImporter(name);  //returns Importer<Organisation>
    var processor = Factory.GetProcessor(name); //returns OrganisationProcessor
    processor.Process(importer.GetObjects()); //.Process takes List<Organisation>
    Console.WriteLine (importer.GetObjects().GetType());
}

public static class Factory
{
    public static Importer GetImporter(string name)
    {           
            //add namespace to name here
        var desiredType = Type.GetType(name);

        return new Importer(desiredType);
    }
    public static Processor GetProcessor(string name)
    {
            //add namespace to name here
        var desiredType = Type.GetType(name+"Processor");

        return (Processor)Activator.CreateInstance(desiredType);
    }
}

public class Importer 
{
    Type _typeOfEntities;

    public Importer(Type typeOfEntities)
    {
        _typeOfEntities = typeOfEntities;
    }
    public IList GetObjects()
    {
        Type generic = typeof(List<>);

        Type constructed = generic.MakeGenericType(new Type[] {_typeOfEntities});

        return (IList)Activator.CreateInstance(constructed);
    }
}
public interface Processor
{
    void Process(IList objects);
}

public class OrganisationProcessor : Processor
{
    public void Process(IList objects)
    {
        var desiredTypedObject = objects as List<Organisation>;
        if(desiredTypedObject != null)
        ProcessImp(desiredTypedObject);
    }
    private void ProcessImp(List<Organisation> objects)
    {
        Console.WriteLine ("processing Organisation");
    }
}

public class AddressProcessor
{
    public void Process(List<Address> objects)
    {
        //Do something by analogy
    }
}

public class Organisation { }

public class Address { }