Search code examples
c#linqobserver-pattern

Can/Should I Linqify this foreach/if/foreach/if/invoke code?


Code I think can be Linq:

    foreach (var key in _dic.Keys) // for each observed key
        if (_changedKeys.Contains(key)) // if it changed
            foreach (var item in _dic[key]) // then for each observer
                if (_webSitePage.Session[key] != null) // , as long as the value is something
                    item(_webSitePage.Session[key]); // call the registered delegate

In context of surrounding code:

public class WebSiteContext
{
    private WebSitePage _webSitePage;

    internal void SetSessionValue<T>(string key, T value)
    {
        object current = _webSitePage.Session[key];
        if (current != null && current.Equals(value)) return;
        _webSitePage.Session[key] = value;
        _changedKeys.Add(key);
    }

    Dictionary<string, List<Action<object>>> _dic = new Dictionary<string, List<Action<object>>>();

    List<string> _changedKeys = new List<string>();

    internal void WhenSessionValueChanges(string key, Action<object> action)
    {
        if (!_dic.ContainsKey(key)) _dic[key] = new List<Action<object>>(); // create on demand
        _dic[key].Add(action);
    }

    internal void PageLoadComplete()
    {
        foreach (var key in _dic.Keys) // for each observed key
            if (_changedKeys.Contains(key)) // if it changed
                foreach (var item in _dic[key]) // then for each observer
                    if (_webSitePage.Session[key] != null) // , as long as the value is something
                        item(_webSitePage.Session[key]); // call the registered delegate

    }
}

public class WebSitePage : System.Web.UI.Page
{
    public WebSitePage()
    {
        this.WebSiteContext = new WebSiteContext(this);
    }

    public WebSiteContext WebSiteContext { get; set; }

    protected override void OnLoadComplete(EventArgs e)
    {
        base.OnLoadComplete(e);
        this.WebSiteContext.PageLoadComplete();
    }
}

Solution

  • It could be changed to LINQ, but since you are calling item(...) for its side-effects, I think using LINQ here is inappropriate and a foreach loop is better.

    You could however write something like this:

     foreach (var key in _dic.Keys.Where(key => _changedKeys.Contains(key))
     {
         foreach (var item in _dic[key])
         {
             var value = _webSitePage.Session[key];
             if (value != null)
             {
                 item(value);
             }
         }
     }