6
\$\begingroup\$

Consider we have three different database stores which we want to find an Id which is unique in all this three. I mean if we query first data store and we find that id. It's over and there is no need to further attempt, if that Id is in non of this three data stores we return null, I'm new in asynchronous programming, I wanted to know if there is any better implementation for this lines of code? I mean less if/else?

 public async Task<WebData> GetDataByIdAsync(GetDataById input)
    {
        var twitterData = await DataAccess.FindDataById<TwitterData>(input.Id);
        WebData result;
        if (twitterData  == null)
        {
            var facebookData = await DataAccess.FindDataById<FacebookData>(input.Id);
            if facebookData == null)
            {
                var linkedinData = await DataAccess.FindDataById<LinkedinData>(input.Id);
                if linkedinData == null)
                {
                    return null;
                }
                result = linkedinData 
            }
            else
            {
                result = facebookData;
            }
        }
        else
        {
            result = twitterData ;
        }
        return result;
    }
\$\endgroup\$
21
\$\begingroup\$

Use the return pattern:

public async Task<WebData> GetDataByIdAsync(GetDataById input) 
{ 
    var twitterData = await DataAccess.FindDataById<TwitterData>(input.Id); 
    if (twitterData != null)
    {
        return twitterData;
    } 

    var facebookData = await DataAccess.FindDataById<FacebookData>(input.Id); 
    if (facebookData != null) 
    {
        return facebookData;
    } 

    var linkedinData = await DataAccess.FindDataById<LinkedinData>(input.Id); 
    if (linkedinData != null) 
    { 
        return linkedinData; 
    }

    return null;
}
\$\endgroup\$
  • 7
    \$\begingroup\$ Are early returns a "pattern" now? \$\endgroup\$ – Bergi Jan 4 '18 at 19:40
  • 1
    \$\begingroup\$ What is actually needed to be called a pattern? \$\endgroup\$ – A Bravo Dev Jan 4 '18 at 19:52
  • 1
    \$\begingroup\$ @ABravoDev: Multiple steps/parts that commonly appear together to solve a common problem, but are not baked into the language. \$\endgroup\$ – cHao Jan 4 '18 at 21:56
  • 1
    \$\begingroup\$ This is crying out for a method to call some DAO with an id. You can the same code 3 times. \$\endgroup\$ – Boris the Spider Jan 5 '18 at 9:43
  • 2
    \$\begingroup\$ @Bergi Probably a code style pattern, not software design pattern. \$\endgroup\$ – interphx Jan 5 '18 at 11:04
52
\$\begingroup\$

Short and clean using null-coalescing operator:

public async Task<WebData> GetDataByIdAsync(GetDataById input) 
{ 
    return await DataAccess.FindDataById<TwitterData>(input.Id)?? 
           await DataAccess.FindDataById<FacebookData>(input.Id)??
           await DataAccess.FindDataById<LinkedinData>(input.Id); 
}
\$\endgroup\$
2
\$\begingroup\$

An efficient way of doing this (if you don't care about the overhead on the data stores) would be to start all three tasks, then return when the first of the tasks produces a non-null value. Something like this:

public async Task<WebData> GetDataByIdAsync(GetDataById input) 
{
    var remainingTasks = new HashSet<Task<WebData>>(new [] { DataAccess.FindDataById<TwitterData>(input.Id), DataAccess.FindDataById<FacebookData>(input.Id), DataAccess.FindDataById<LinkedinData>(input.Id) });

    while (remainingTasks.Any())
    {
        var firstCompleted = await Task.WhenAny(remainingTasks);
        if (firstCompleted.Result != null)
        {
             return firstCompleted.Result;
        }
        remainingTasks.Remove(firstCompleted);
    }

    return null;
}
\$\endgroup\$
  • \$\begingroup\$ One downside to this approach is that you launch all three tasks and if one returns, any exceptions thrown by the later tasks go unobserved. \$\endgroup\$ – Dan Bryant Jan 4 '18 at 16:07
  • 1
    \$\begingroup\$ This wouldn't work if you cared about order, would it? e.g. if Facebook is fastest but you would prefer to use Twitter if available? Also, it's effectively non-deterministic and could produce different results if you run it multiple times. \$\endgroup\$ – Bob Jan 5 '18 at 1:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.