从一个ID创建从一个对象(或名称)对象、名称、ID

2023-09-04 00:21:37 作者:套路用尽只想撩你

我有很多子类继承抽象类:

I have an abstract class that a lot of child classes inherit:

  public abstract class CrawlerBase
    {
        public abstract void Process(string url);
    }

我工作的这个循环:

I'm working on this loop:

foreach (var item in result)
                {
                    object crawler = null;

                    switch (item.Type)
                    {
                        case "Trials":
                            var t = new Trials(); 
                            ct.Process(item.URL); //repetitive code.  
                            break;

                        case "Coverage":
                            var c = new Coverage();
                            c.Process(item.URL); //repetitive code.
                            break;
                        default:
                            break;
                    }

                   // crawler.Process(item.URL);
                }

现在的项目。形式的字符串将取决于需要被实例化什么子类。由于我的所有子类继承我的基类,那将是非常重复调用.Process()在每一个case语句。我想投的对象爬虫的子类被实例化,并调用crawler.Process()在switch语句的结束,如图中的注释。我怎样才能做到这一点?

Now the item.type string will depend on what child class needs to be instantiated. Since all my child classes inherit my base class, it would be very repetitive to call .Process() in every case statement. I want to cast the object "crawler" to the child class being instantiated, and call the crawler.Process() at the end of the switch statement, as shown in the comments. How can I do this?

推荐答案

有许多方法来创建一个字符串类型。反射可以是其中之一,它的慢(但如果你正在处理Web请求可能你不会在意这个问题),但你不会需要保持硬$ C一长串$ CD字符串和/或拥有一个丑陋长的开关/ case语句。

There are many way to create a type from a string. Reflection can be one of them, it's slow (but if you're processing web requests probably you won't care of this) but you won't need to keep a long list of hard-coded strings and/or to have an ugly long switch/case statement.

如果速度不是问题,那么让我们开始与一些简单的:

If speed is not a problem then let's start with something easy:

CrawlerBase crawler = (CrawlerBase)Activator.CreateInstance(
    Type.GetType("MyNamespace." + item.Type));

crawler.Process(item.URL);

使用反射你不需要开关/箱,并不要紧,你有多少类型都有,你会不会改变你的工厂code,以适应 CrawlerBase 。只需添加一个新的实现等,瞧。

Using reflection you do not need switch/case and, it doesn't matter how many types you have, you won't change your factory code to accomodate new implementations of CrawlerBase. Simply add a new implementation et-voila.

它是如何工作的?那么你可以创建从键入定义(使用的 Activator.CreateInstance ),所以的问题的是让类型键入类提供了一个静态 的GetType 方法,可以用来创建一个从它的(全)名称类型。在这种情况下,我们提供一个命名空间,则必须更改为真实的,如果你把所有的类相同的命名空间,你可以这样写:

How it works? Well you can create an instance of a class from its Type definition (using Activator.CreateInstance) so the problem is to get the Type. Type class provides a static GetType method that can be used to create a Type from its (full) name. In this case we supply a namespace, it must be changed to the real one, if you keep all your classes in the same namespace you may write something like this:

string rootNamespace = typeof(CrawlerBase).Namespace;

和再maked后续版本:

And then the maked-up version:

CrawlerBase crawler = (CrawlerBase)Activator.CreateInstance(
    Type.GetType(rootNamespace + "." + item.Type));

crawler.Process(item.URL);

改进1

这是一个很幼稚的实现,更好的版本应该缓存键入词典中的:

private static Dictionary<string, Type> _knownTypes =
    new Dictionary<string, Type>();

private static GetType(string name)
{
    string fullName = typeof(CrawlerBase).Namespace
        + "." + name;

    if (_knownTypes.ContainsKey(fullName))
        return _knownTypes[fullName];

    Type type = Type.GetType(fullName);
    _knownTypes.Add(fullName, type);

    return type;
}

现在你行,你就不需要管理(可能)长串的名单,你不需要改变一个无休止的开关/情况下,如果你添加/删除/修改类型和添加新的履带式所有你需要做的就是派生新类。请注意,这个功能是不是线程安全的话,如果你有多个线程,你必须增加一个锁来保护字典访问(或 ReadWriterLockSlim ,它取决于你的使用模式)。

Now you're OK, you do not need to manage a (possibly) long list of strings, you do not need to change an endless switch/case if you add/remove/change a type and to add a new Crawler all you have to do is to derive a new class. Please note that this function isn't thread-safe so, if you'll have multiple threads, you have to add a lock to protect dictionary access (or a ReadWriterLockSlim, it depends on your usage pattern).

接下来是什么?如果您需要的资料的要求更加严格(安全性,例如),您可能需要增加更多的东西(我认为这不是你的情况,所以你可能甚至不需要类型字典)。什么做多?首先,你可以检查创建的类型从 CrawlerBase 导出(使用 IsAssignableFrom ,并提供一个更有意义的异常,而不是 InvalidCastException的),第二你可以装饰你的类与属性。只有等级与属性将被创建,(这样可以保持的私人的,即使标记为公开的实现不能从你的用户创建的)。还有比这更,但一个简单的实现通常就足以解决这类问题(当输入并非来自用户,但来自强劲的配置文件或程序本身)。

What's next? If your're requirements are more strict (about security, for example) you may need to add something more (I think it's not your case so you may not even need the type dictionary). What to do more? First you may check that the created type derives from CrawlerBase (using IsAssignableFrom and to provide a more meaningful exception instead of InvalidCastException), second you may decorate your classes with an attribute. Only classes with that attributes will be created (so you can keep private implementations that even if marked as public cannot be created from your users). There is much more than this but a simple implementation usually is enough to solve this kind of problems (when the input doesn't come from user but from robust configuration file or from the program itself).