0

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

例如,我想调用Importer<Organisation>.GetObjects()并让它返回一个List<Organisation>. 然后将列表传递给我的 OrganisationProcessor。

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

我想将Importer<>and *Processor 的创建放入工厂。我已经删除了所有代码并在下面生成了一个未受污染的样本。我的尝试没有成功,可能归结为我不完全理解的方差之类的话题。

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 { }
4

4 回答 4

2

这应该可以解决问题,请注意您的最初意图没有改变,这甚至让我感到惊讶。另请注意,您必须添加命名空间才能在 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 { }
于 2012-08-22T08:13:48.210 回答
1

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 方法类似于

public static object GetImporter(string name)
{
    Type type = Type.GetType(name);
    Type importerType = typeof(Importer<>).MakeGenericType(type);
    return Activator.CreateInstance(importerType);
}

最后,GetProcessor 将类似于

public static object GetProcessor(string name)
{
    Type type = Type.GetType(name + "Processor");
    return Activator.CreateInstance(type);
}

请注意,传入的字符串名称必须是类型的全名,包括命名空间,并且仅限于与这些方法位于同一程序集中的类型(组织、地址)。如果要在其他程序集中使用类型,则必须使用程序集限定名称,但是用于生成处理器类型名称的字符串连接将不起作用。

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

于 2012-08-22T08:09:02.747 回答
1

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

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);
    }
}

因此,您使用上面的工厂,如下所示:

dynamic importer = Factory.GetImporter(name);
dynamic processor = Factory.GetProcessor(name);
processor.Process(importer.GetObjects());
于 2012-08-22T08:10:54.470 回答
0

在您的工厂中,Get... 方法可以使用Activator.CreateInstance 方法。此方法可以通过带有附加参数的 assamby-name 和 type-name 创建类的实例。

于 2012-08-22T07:41:27.903 回答