2010-08-29 29 views
0

目前,我有一个静态的工厂方法是这样的:使用Dictionary来映射工厂方法与匿名函数/委托以加快查找速度?

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语句)?

这是一个类似的问题,但遗憾的是笔者并不IFS VS代表发表他的代码Enum, Delegate Dictionary collection where delegate points to an overloaded method

更新

做了一些性能基准。我随机选取了单元代码,并为这两种方法使用了相同的种子。代表版本实际上稍慢。这些代表正在造成某种开销。我使用发布版本运行。

5000000 iterations 
CreateFromCodeIf ~ 9780ms 
CreateFromCodeDelegate ~ 9990ms 

回答

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

你是否有招聘?一小时收取多少钱? :D伟大的解决方案。我喜欢它比Keltex更紧凑。替代解决方案其实非常好。 – randomguy 2010-08-29 02:14:04

+0

对于上述两种方法,我都得到了“代理”System.Action '不带0个参数“。 – randomguy 2010-08-29 02:24:18

+0

@randomguy:将其更改为'Func';抱歉。 – SLaks 2010-08-29 02:42:49

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

好的,先生。会接受SLaks的答案,但是给你一个快艇。 – randomguy 2010-08-29 02:14:59

0

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

  1. BookResource bookResourceEnum =(BookResource)Enum。解析(typeof运算(BookResource)的bookcode);

    return new Book(bookResourceEnum);

  2. 或者更好的是,让你的静态工厂方法创建接受BookResource代替的bookcode,让客户不用担心从代码转换为枚举,这样 没有人能不能被映射到BookResource代码通过。

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

+0

嘿!感谢您的输入。是从.resx文件自动生成的文化敏感资源类,因此按照您的建议使用它是没有意义的,或者至少它对我没有意义,我同意所有最后的观点,不过,我确实认为委托方法非常好。如果开销不是很大。 – randomguy 2010-08-30 22:29:23