C# 反思与反思;应用程序设计

C# 反思与反思;应用程序设计,c#,reflection,appdomain,C#,Reflection,Appdomain,让我描述一下我目前面临的问题和解决方案,也许你可以帮助我了解为什么这是一个坏主意(假设是),以及我能做些什么使它成为一个更好的系统 现在我有600个“裂土器”,可以解析文件并将它们裂成csv或其他格式。裂土器都实现了一个通用接口和基类。当作业根据该作业的配置排队时,使用反射调用特定裂土器 foreach (var stream in streams) { try {

让我描述一下我目前面临的问题和解决方案,也许你可以帮助我了解为什么这是一个坏主意(假设是),以及我能做些什么使它成为一个更好的系统

现在我有600个“裂土器”,可以解析文件并将它们裂成csv或其他格式。裂土器都实现了一个通用接口和基类。当作业根据该作业的配置排队时,使用反射调用特定裂土器

            foreach (var stream in streams)
            {
                try
                {
                    // load it
                    Assembly asm = Assembly.LoadFile(Path.Combine(stream.RipperPath, stream.RipperFileName), new Evidence());
                    if (asm == null)
                    {
                        MessageBox.Show(String.Format("Invalid Interface ripper loaded.\n{0}", Path.Combine(stream.RipperPath, stream.RipperFileName)));
                        return;
                    }

                    foreach (Type objType in asm.GetTypes())
                    {
                        if (!objType.IsPublic)
                            continue;

                        // make sure the type isn't Abstract
                        if (((objType.Attributes & TypeAttributes.Abstract) == TypeAttributes.Abstract))
                            continue;

                        // IRipper is the interface that all of the Rippers must implement to be loaded
                        Type objInterface = objType.GetInterface("IRipper", true);
                        if (objInterface == null)
                            continue;

                        try
                        {
                            var iri = (IRipper)Activator.CreateInstance(objType);

                            // Rippers must register with their hosts
                            iri.Host = this;
                            iri.OnStart += RipperStart;
                            iri.OnComplete += RipperComplete;
                            iri.OnProgressChanged += RipperStatusUpdate;
                            iri.dataStream = stream;
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(String.Format("Error loading interface: {0}\n{1}", Path.Combine(stream.RipperPath, stream.RipperFileName), ex.Message));
                }
            } 
所有裂土器都实现了一个名为“Rip()”的函数,接口将其收缩到该函数

使用当前代码,我能看到的唯一问题是,在加载600个程序集后(因为它们是在需要时加载的),如果在使用它们之后不卸载它们,则会开始变得有点慢


您有什么建议?

您实际上有600种不同的裂土器,还是600种流和一些数量较少的裂土器?您真的需要每个裂土器都有自己的组件吗?如果你能把裂土器捆在一起,你的总成就会少得多。如果流详细信息包含类型名称和可执行文件,则可以有多个裂土器,而无需在程序集中查找它们-只需调用
assembly.GetType

我不知道每个程序集的实际开销是多少,请注意,我希望600个程序集占用相当多的内存,但除此之外不会对性能产生太大的影响


整体方法似乎是合理的,尽管您可能还想查看-对于您的案例来说,这可能有些过分,但值得一看。我要做的另一件事是从“处理流”代码中剔除“获取裂土器”:)

您实际上有600个不同的裂土器,还是600个流和一些较小数量的裂土器?您真的需要每个裂土器都有自己的组件吗?如果你能把裂土器捆在一起,你的总成就会少得多。如果流详细信息包含类型名称和可执行文件,则可以有多个裂土器,而无需在程序集中查找它们-只需调用
assembly.GetType

我不知道每个程序集的实际开销是多少,请注意,我希望600个程序集占用相当多的内存,但除此之外不会对性能产生太大的影响


整体方法似乎是合理的,尽管您可能还想查看-对于您的案例来说,这可能有些过分,但值得一看。我要做的另一件事是从“处理流”代码中计算出“获取裂土器”:)

您可能想看看这些东西。外接程序似乎加载到了它们自己的应用程序域中,这使得在不再需要它们时可以干净地卸载它们。

您可能想看看这些东西。外接程序似乎加载到它们自己的应用程序域中,这使得在不再需要它们时可以干净地卸载它们。

谢谢John-我有每个裂土器的完整路径,它们也都使用相同的界面,有几个近600裂土器--非常自定义的文件格式,无法组合,但您真的需要每个裂土器都在自己的程序集中吗?难道你不能把它们放在一个单独的程序集中,然后参考流信息中的类型吗?从10个程序集中加载600个类型听起来比600个程序集(每个程序集中有一个类型)更合理。Jon我在你的想法中遇到的一个问题是,它们都是同一类型的“IRipper”-我不知道在运行时实现IRipper的类名-我如何区分要调用的类?正如我所说,您应该在当前指定程序集文件名的同一位置指示类型名称。谢谢John-我有每个裂土器的完整路径,它们也使用相同的接口,有几个近600裂土器--非常自定义的文件格式,无法组合,但您真的需要每个裂土器都在自己的程序集中吗?难道你不能把它们放在一个单独的程序集中,然后参考流信息中的类型吗?从10个程序集中加载600个类型听起来比600个程序集(每个程序集中有一个类型)更合理。Jon我在你的想法中遇到的一个问题是,它们都是同一类型的“IRipper”-我不知道在运行时实现IRipper的类名-我如何区分要调用的类?正如我所说,您应该在当前指定程序集文件名的同一位置指示类型名称。