c# ConcurrentDictionary 用惰性包装 AddOrUpdate 不编译
c# ConcurrentDictionary wrapping AddOrUpdate with lazy doesn't compile
我想创建一个新的 class 来包装当前的 .net ConcurrentDictionary,以便确保 GetOrAdd\AddOrUpdate 的添加委托只被调用一次。我在网上看到了几个解决方案,主要的一个是用 lazy 包装 TValue 以便可以添加许多惰性项,但只有一个会存活并调用它的值工厂。
这是我想出的:
public class LazyConcurrentDictionary<TKey, TValue>
{
private readonly ConcurrentDictionary<TKey, Lazy<TValue>> concurrentDictionary;
public LazyConcurrentDictionary()
{
this.concurrentDictionary = new ConcurrentDictionary<TKey, Lazy<TValue>>();
}
public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
{
var lazyResult = this.concurrentDictionary.GetOrAdd(key, k => new Lazy<TValue>(() => valueFactory(k), LazyThreadSafetyMode.ExecutionAndPublication));
return lazyResult.Value;
}
public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addFactory, Func<TKey, TValue> updateFactory)
{
// this one fails with "Cannot convert lambda expression to type 'System.Lazy' because it is not a delegate type"
var lazyResult = this.concurrentDictionary.AddOrUpdate(key, (k) => new Lazy<TValue>( () => addFactory(k), LazyThreadSafetyMode.ExecutionAndPublication), updateFactory);
return lazyResult.Value;
}
}
我的问题是 AddOrUpdate 签名,我得到 "Cannot convert lambda expression to type 'System.Lazy' because it is not a delegate type"
我做错了什么?
我认为您误解了此函数的 updateFactory 的含义。它是从TKey
、TValue
到TValue
的函数,而不是从TKey
到TValue
的函数,它应该从旧值计算更新值。
所以正确的语法应该是这样的:
public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addFactory,
Func<TValue, TValue> updateFactory)
{
var lazyResult = this.concurrentDictionary.AddOrUpdate(key,
(k) => new Lazy<TValue>(() => addFactory(k),
LazyThreadSafetyMode.ExecutionAndPublication),
(k,v)=>new Lazy<TValue>(()=>updateFactory(v.Value)))
);
return lazyResult.Value;
}
甚至(取决于你想如何使用它):
public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addFactory,
Func<TKey, TValue, TValue> updateFactory)
{
var lazyResult = this.concurrentDictionary.AddOrUpdate(key,
(k) => new Lazy<TValue>(() => addFactory(k), LazyThreadSafetyMode.ExecutionAndPublication),
(k,v)=>new Lazy<TValue>(()=>updateFactory(k, v.Value))
);
return lazyResult.Value;
}
我想创建一个新的 class 来包装当前的 .net ConcurrentDictionary,以便确保 GetOrAdd\AddOrUpdate 的添加委托只被调用一次。我在网上看到了几个解决方案,主要的一个是用 lazy 包装 TValue 以便可以添加许多惰性项,但只有一个会存活并调用它的值工厂。
这是我想出的:
public class LazyConcurrentDictionary<TKey, TValue>
{
private readonly ConcurrentDictionary<TKey, Lazy<TValue>> concurrentDictionary;
public LazyConcurrentDictionary()
{
this.concurrentDictionary = new ConcurrentDictionary<TKey, Lazy<TValue>>();
}
public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
{
var lazyResult = this.concurrentDictionary.GetOrAdd(key, k => new Lazy<TValue>(() => valueFactory(k), LazyThreadSafetyMode.ExecutionAndPublication));
return lazyResult.Value;
}
public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addFactory, Func<TKey, TValue> updateFactory)
{
// this one fails with "Cannot convert lambda expression to type 'System.Lazy' because it is not a delegate type"
var lazyResult = this.concurrentDictionary.AddOrUpdate(key, (k) => new Lazy<TValue>( () => addFactory(k), LazyThreadSafetyMode.ExecutionAndPublication), updateFactory);
return lazyResult.Value;
}
}
我的问题是 AddOrUpdate 签名,我得到 "Cannot convert lambda expression to type 'System.Lazy' because it is not a delegate type"
我做错了什么?
我认为您误解了此函数的 updateFactory 的含义。它是从TKey
、TValue
到TValue
的函数,而不是从TKey
到TValue
的函数,它应该从旧值计算更新值。
所以正确的语法应该是这样的:
public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addFactory,
Func<TValue, TValue> updateFactory)
{
var lazyResult = this.concurrentDictionary.AddOrUpdate(key,
(k) => new Lazy<TValue>(() => addFactory(k),
LazyThreadSafetyMode.ExecutionAndPublication),
(k,v)=>new Lazy<TValue>(()=>updateFactory(v.Value)))
);
return lazyResult.Value;
}
甚至(取决于你想如何使用它):
public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addFactory,
Func<TKey, TValue, TValue> updateFactory)
{
var lazyResult = this.concurrentDictionary.AddOrUpdate(key,
(k) => new Lazy<TValue>(() => addFactory(k), LazyThreadSafetyMode.ExecutionAndPublication),
(k,v)=>new Lazy<TValue>(()=>updateFactory(k, v.Value))
);
return lazyResult.Value;
}