Создать объект, зная только имя класса?

Вот небольшая программа, которая удаляет комментарии C почти во всех случаях.

/* strip C comments by chqrlie */

#include <errno.h>
#include <stdio.h>
#include <string.h>

/* read the next byte from the C source file, handing escaped newlines */
int getcpp(FILE *fp, int *lineno_p) {
    int ch;
    while ((ch = getc(fp)) == '\\') {
        if ((ch = getc(fp)) != '\n') {
            ungetc(ch, fp);
            return '\\';
        }
        *lineno_p += 1;
    }
    if (ch == '\n')
        *lineno_p += 1;
    return ch;
}

int main(int argc, char *argv[]) {
    FILE *fp = stdin, *ft = stdout;
    const char *filename = "<stdin>";
    int ch, lineno;

    if (argc > 1) {
        if ((fp = fopen(filename = argv[1], "r")) == NULL) {
            fprintf(stderr, "Cannot open input file %s: %s\n",
                    filename, strerror(errno));
            return 1;
        }
    }
    if (argc > 2) {
        if ((ft = fopen(argv[2], "w")) == NULL) {
            fprintf(stderr, "Cannot open output file %s: %s\n",
                    argv[2], strerror(errno));
            return 1;
        }
    }
    lineno = 1;
    while ((ch = getcpp(fp, &lineno)) != EOF) {
        int startline = lineno;
        if (ch == '/') {
            if ((ch = getcpp(fp, &lineno)) == '/') {
                /* single-line comment */
                while ((ch = getcpp(fp, &lineno)) != EOF && ch != '\n')
                    continue;
                if (ch == EOF) {
                    fprintf(stderr, "%s:%d: unterminated single line comment\n",
                            filename, startline);
                    break;
                }
                putc('\n', ft);  /* replace comment with newline */
                continue;
            }
            if (ch == '*') {
                /* multi-line comment */
                int lastc = 0;
                while ((ch = getcpp(fp, &lineno)) != EOF) {
                    if (ch == '/' && lastc == '*') {
                        break;
                    }
                    lastc = ch;
                }
                if (ch == EOF) {
                    fprintf(stderr, "%s:%d: unterminated comment\n",
                            filename, startline);
                    break;
                }
                putc(' ', ft);  /* replace comment with single space */
                continue;
            }
            putc('/', ft);
            /* keep parsing to handle n/"a//"[i] */
        }
        if (ch == '\'' || ch == '"') {
            int sep = ch;
            const char *const_type = (ch == '"') ? "string" : "character";

            putc(sep, ft);
            while ((ch = getcpp(fp, &lineno)) != EOF) {
                putc(ch, ft);
                if (ch == sep)
                    break;;
                if (ch == '\\') {
                    if ((ch = getcpp(fp, &lineno)) == EOF)
                        break;
                    putc(ch, ft);
                }
                if (ch == '\n') {
                    fprintf(stderr, "%s:%d: unescaped newline in %s constant\n",
                            filename, lineno - 1, const_type);
                    /* This is a syntax error but keep going as if constant was terminated */
                    break;
                }
            }
            if (ch == EOF) {
                fprintf(stderr, "%s:%d: unterminated %s constant\n",
                        filename, startline, const_type);
                break;
            }
            continue;
        }
        putc(ch, ft);
    }
    if (fp != stdin)
        fclose(fp);
    if (ft != stdout)
        fclose(ft);
    return 0;
}

Поскольку вы получите полный ответ бесплатно, попробуйте и узнайте, как приведенный выше код обрабатывает строки и экранированные символы новой строки. Есть еще некоторые угловые случаи, которые не поддерживаются, можете ли вы их найти?

  • Одним из таких угловых случаев является то, что код не анализирует триграфы, устаревшая особенность, которая может использоваться для сокрытия \ символов. .
15
задан Anthony Mastrean 17 November 2008 в 17:32
поделиться

4 ответа

Так как Вы знаете, что все классы будут прибывать из того же пространства имен, настроить его однажды и использование что:

<appConfig>
   <SuperAppConfig handlerNamespace="BigCorp.SuperApp">
      <Handler class="ClassB" />
   </SuperAppConfig>
</appConfig>

Редактирование: я изменился имя к класс для лучше обозначения значения того атрибута.

6
ответ дан 1 December 2019 в 01:54
поделиться

Или используйте полностью определенное имя блока, или овладейте блоком и используйте Assembly.GetType(name). В этом случае, так как Вы хотите типы в файле конфигурации, квалифицированный к блоку допустимый способ пойти - но так как Вы знаете, что все Ваши типы находятся в том же блоке:

Assembly assembly = typeof(SomeKnownType).Assembly; // in the same assembly!
Type type = assembly.GetType(name); // full name - i.e. with namespace (perhaps concatenate)
object obj = Activator.CreateInstance(type);

помехи Type.GetType(string) имеют правила зондирования, которые часто вызывают беспорядок... это смотрит на блок вызова, и несколько системных блоков - но не все загруженные блоки.

18
ответ дан 1 December 2019 в 01:54
поделиться
(I will not be loading a type from outside this assembly/namespace)

из-за вышеупомянутой строки, безопасно предположить, что Вы знаете, каково пространство имен. Не могли Вы делать что-то как:

Type t = Type.GetType("Namespace." + className); 
BaseClass c = Activator.CreateInstance(t) as BaseClass; 

, Если Вы ожидаете возможно мочь добавить дополнительные классы стратегии, которые будут загружены в будущем, возможно, через дополнительный блок, необходимо было бы полностью определить имя класса. Это рекомендуется так или иначе, так как Вы смогли бы обеспечить улучшенный extendability для своего приложения.

5
ответ дан 1 December 2019 в 01:54
поделиться

Я иду с полным именем типа в конфигурации приложения. Ниже немного больше полного, но все еще тривиального примера

<SuperAppConfig>
   <ObjectConfig provider="BigCorp.SuperApp.ClassA">
      <add name="one" />
      <add name="two" />
   </ObjectConfig>
</SuperAppConfig>

И класс фабрики, который на самом деле создает это

private static Assembly a = typeof(IFactoryObject).Assembly;
public static IFactoryObject CreateObject(String providerName)
{
    Type t = a.GetType(providerName)
    IFactoryObject o = Activator.CreateInstance(t) as IFactoryObject;
    return o;
}
2
ответ дан 1 December 2019 в 01:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: