2017-02-13 23 views
1

Я хочу создать новый класс, который будет обертывать текущий .net ConcurrentDictionary, чтобы обеспечить добавление делегата из GetOrAdd \ AddOrUpdate для вызова только один раз. Я видел пару решений в сети, а главное - обернуть TValue ленивым, чтобы можно было добавить много ленивых элементов, но только один выживет и вызовет его фабрику значений.C# ConcurrentDictionary wrapping AddOrUpdate с lazy не компилируется

вот что я придумал:

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, я получаю «Не удается преобразовать лямбда-выражения к типу„System.Lazy“, потому что это не тип делегата»

Что я делаю неправильно?

ответ

1

Я думаю, что вы пропустили понимаемый смысл 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; 
} 

или даже (в зависимости от того, как вы wnat использовать):

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

конечно, компилятор подчеркнуты ошибку при надстройке делегата, так что я «Пропустил это, спасибо Максиму! – Ofir