使用Dictionary来使用匿名函数/委托映射工厂方法以加快查找速度?

时间:2010-08-29 01:43:48

标签: c# .net dictionary anonymous-function anonymous-delegates

目前,我有一个像这样的静态工厂方法:

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个图书代码(因此&lt; 50 if-statements),这是否值得加速?

这是一个类似的问题,但不幸的是作者没有发布他的代码Enum, Delegate Dictionary collection where delegate points to an overloaded method

更新

是否对代表进行了一些绩效基准测试。我随机选择了单位代码,并为这两种方法使用了相同的种子。委托版本实际上稍慢。那些代表正在造成某种开销。我在运行时使用了发布版本。

5000000 iterations
CreateFromCodeIf ~ 9780ms
CreateFromCodeDelegate ~ 9990ms

3 个答案:

答案 0 :(得分:2)

像这样:

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类。

尽管lambda表达式是非类型化表达式,但它们可以在需要委托类型的位置使用(例如索引器赋值),并隐式假定委托的类型。

你也可以写

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

我建议您更改字典以包含BookResource,如下所示:

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

答案 1 :(得分:2)

坦率地说,你可能不会注意到两者之间的性能差异。但是,如果您要使用“功能”版本,我不会只使用通用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 :(得分:0)

randomguy,你为什么这么复杂?在你的问题和随后的答案中避免这种混乱的两种方法。

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

    返回新书(bookResourceEnum);

  2. 或者更好的是,创建静态工厂方法创建接受BookResource而不是BookCode,让客户担心从代码到枚举的转换,以便 没有人可以传入无法映射到BookResource的代码。

  3. 说真的,如果你给我写了一个50“如果”的代码,或者更糟糕的是有50个“代表”,我们会有一个“谈话”。当你不确定那是你的瓶颈时,尽量避免过早优化(如果有的话)。应该首先考虑可读性和可维护性。