Отображать фабричные методы с анонимными функциями / делегатами, используя словарь для более быстрого поиска? - PullRequest
0 голосов
/ 29 августа 2010

В настоящее время у меня есть статический фабричный метод, подобный этому:

public static Book Create(BookCode code) {
    if (code == BookCode.Harry) return new Book(BookResource.Harry);
    if (code == BookCode.Julian) return new Book(BookResource.Julian);
    // etc.
}

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

Выполнение этих if-утверждений возможно с точки зрения скорости. Но что если мы сопоставим коды книг с анонимными функциями / делегатами? Примерно так:

delegate Book Create();
private static Dictionary<BookCode, Delegate> ctorsByCode = new Dictionary<BookCode, Delegate>();
// Set the following somewhere
// not working!
ctorsByCode[BookCode.Harry] = Create () => { return new Book(BookResource.Harry); }
// not working!
ctorsByCode[BookCode.Julian] = Create () => { return new Book(BookResource.Julian); } 
public static Book Create(BookCode code) {
    return (Book)ctorsByCode[code].DynamicInvoke(null);
}

Как я мог заставить эти Create() => { строки реально работать?

Стоит ли это ускорять, когда существует <50 кодов книг (то есть <50 операторов if)? </p>

Это аналогичный вопрос, но, к сожалению, автор не публикует свой код Enum, коллекция словаря делегатов, где делегат указывает на перегруженный метод

Обновление

Сделал некоторые тесты производительности, если против делегатов. Я выбрал код единицы случайным образом и использовал одинаковое начальное число для обоих методов. Версия делегата на самом деле немного медленнее. Эти делегаты вызывают какие-то накладные расходы. Я использовал релизные сборки для прогонов.

5000000 iterations
CreateFromCodeIf ~ 9780ms
CreateFromCodeDelegate ~ 9990ms

Ответы [ 3 ]

2 голосов
/ 29 августа 2010

Честно говоря, вы, вероятно, не заметите большой разницы в производительности между ними.Но если вы собираетесь использовать «функциональную» версию, я бы не просто использовал общий Delegate, но вместо этого передал делегат, который вы только что создали.Так что это будет ваш (более простой) код:

delegate Book Create();
private static Dictionary<BookCode, Create> ctorsByCode 
    = new Dictionary<BookCode, Create>();

ctorsByCode[BookCode.Harry] = () => new Book(BookResource.Harry);
ctorsByCode[BookCode.Julian] = () => new Book(BookResource.Julian); 

public static Book Create(BookCode code) {
    return ctorsByCode[code]();
}
2 голосов
/ 29 августа 2010

Например:

private static readonly Dictionary<BookCode, Func<Book>> ctorsByCode = new Dictionary<BookCode, Func<Book>>();

...

ctorsByCode[BookCode.Harry] = () => new Book(BookResource.Harry);

public static Book Create(BookCode code) {
    return ctorsByCode[code]();
}

Тип Func<Book> - это предопределенный универсальный тип делегата, который вы можете использовать вместо создания своего.
Кроме того, ваш словарь должен содержать определенный делегат.тип, а не базовый Delegate класс.

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

Вы также можете написать

ctorsByCode[BookCode.Harry] = new Func<Book>(() => new Book(BookResource.Harry));

Я бы порекомендовал заменить ваш словарь на BookResource s, например, так:

private static readonly Dictionary<BookCode, BookResource> codeResources = new Dictionary<BookCode, BookResource>();

...

codeResources[BookCode.Harry] = BookResource.Harry;

public static Book Create(BookCode code) {
    return new Book(codeResources[code]);
}
0 голосов
/ 30 августа 2010

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

  1. BookResource bookResourceEnum = (BookResource) Enum.Parse (typeof (BookResource), bookCode);

    вернуть новую книгу (bookResourceEnum);

  2. Или еще лучше, заставить ваш статический метод фабрики Создать accept BookResource вместо BookCode, и пусть клиенты беспокоятся о преобразовании из кода в enum такчто никто не может передать код, который не может быть сопоставлен с BookResource.

Серьезно, если бы вы написали мне код с 50 «если» или еще хуже с 50 «делегатами», мы получили быразговор".Старайтесь избегать преждевременной оптимизации (если есть), когда вы не уверены, что это ваша горлышко бутылки.Читаемость и ремонтопригодность должны быть на первом месте.

...