Let's say, we have the first call GetDefaultData (GetData() executes in 100ms), and then we have 10 calls(GetDefaultData() per 10ms). I want that this rest of calls will get the same answer as the first one.
It sounds like you want the Lazy<T>
class.
public class YourClass
{
private readonly Lazy<Data> _lazyData;
public YourClass()
{
_lazyData = new Lazy<Data>(() => GetData());
}
private Data GetDefaultData()
{
return _lazyData.Value;
}
public Data GetData()
{
//...
}
}
The first thread to call GetDefaultData()
will run GetData()
when it hits _lazyData.Value
, all the rest of the threads will block on the call _lazyData.Value
till the first thread finishes and use the result from that first thread's call. GetData()
will only ever be called once.
If you don't want the call to block you can easily make a AsyncLazy<T>
class that uses Threads internally.
public class AsyncLazy<T> : Lazy<Task<T>>
{
public AsyncLazy(Func<T> valueFactory) :
base(() => Task.Run(valueFactory))
{
}
public AsyncLazy(Func<Task<T>> taskFactory, bool runFactoryInNewTask = true) :
base(() => runFactoryInNewTask ? Task.Run(taskFactory) : taskFactory())
{
}
//This lets you use `await _lazyData` instead of doing `await _lazyData.Value`
public TaskAwaiter<T> GetAwaiter()
{
return Value.GetAwaiter();
}
}
Then your code becomes (I also made GetData an async function too, but the overloads of AsyncLazy
let it be either or)
public class YourClass
{
private readonly AsyncLazy<Data> _lazyData;
public YourClass()
{
_lazyData = new AsyncLazy<Data>(() => GetData(), false);
}
private async Task<Data> GetDefaultData()
{
//I await here to defer any exceptions till the returned task is awaited.
return await _lazyData;
}
public Task<Data> GetData()
{
//...
}
}
EDIT: There are some possible issues with AsyncLazy, see here.