Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. best way to Lazy-Load a Dictionary' s 'Values ?

best way to Lazy-Load a Dictionary' s 'Values ?

Scheduled Pinned Locked Moved C#
csharpdelphisalesquestion
7 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    B Offline
    BillWoodruff
    wrote on last edited by
    #1

    Here's one way:

    // code here uses .NET 4.7

    // in a NameSpace
    public enum Divisions
    {
    Undefined,
    Admin,
    Finance,
    Sales,
    Research,
    IT,
    Temp
    }

    // in a Class: assume 'Person is a typical POCO
    public Dictionary>> DivisionToStaff { set; get; } =
    new Dictionary>>();

    // initialization : typically done in a 'ctor
    public Initialize()
    {
    foreach (Divisions div in Enum.GetValues(typeof(Divisions)))
    {
    DivisionToStaff.Add(div, new Lazy>());
    }
    }

    // sample use case:
    // DivisionToStaff[personInstance.Division].Value.Add(personInstance);

    Do you know a better way ? thanks, Bill

    «When I consider my brief span of life, swallowed up in an eternity before and after, the little space I fill, and even can see, engulfed in the infinite immensity of spaces of which I am ignorant, and which know me not, I am frightened, and am astonished at being here rather than there; for there is no reason why here rather than there, now rather than then.» Blaise Pascal

    A Richard DeemingR 2 Replies Last reply
    0
    • B BillWoodruff

      Here's one way:

      // code here uses .NET 4.7

      // in a NameSpace
      public enum Divisions
      {
      Undefined,
      Admin,
      Finance,
      Sales,
      Research,
      IT,
      Temp
      }

      // in a Class: assume 'Person is a typical POCO
      public Dictionary>> DivisionToStaff { set; get; } =
      new Dictionary>>();

      // initialization : typically done in a 'ctor
      public Initialize()
      {
      foreach (Divisions div in Enum.GetValues(typeof(Divisions)))
      {
      DivisionToStaff.Add(div, new Lazy>());
      }
      }

      // sample use case:
      // DivisionToStaff[personInstance.Division].Value.Add(personInstance);

      Do you know a better way ? thanks, Bill

      «When I consider my brief span of life, swallowed up in an eternity before and after, the little space I fill, and even can see, engulfed in the infinite immensity of spaces of which I am ignorant, and which know me not, I am frightened, and am astonished at being here rather than there; for there is no reason why here rather than there, now rather than then.» Blaise Pascal

      A Offline
      A Offline
      Afzaal Ahmad Zeeshan
      wrote on last edited by
      #2

      I have never used Lazy loading in my own applications, for various reasons. Anyways, looking at your code, Bill, I can say if I had to implement "lazy" loading like feature here, I would simply just set it to null. In most cases of Lazy loading — for instance, the Entity Framework navigation — the types are null, unless you actually specify to need them. Then, once it is required, I would load the data using the yield operator; giving me somewhat relative of the lazy loading. But my answers depends on the way you fetch the List, from database perhaps? I have not yet tried .NET 4.7 by now. :( Does it include anything new? Shiv provides a good overview, and to rewrite that in a different way, would require the understanding that he provides here, [Can you explain Lazy Loading?](https://www.codeproject.com/Articles/652556/Can-you-explain-Lazy-Loading) [Lazy Loading By Using C# Yield Statements | Freaking Awesome](http://blog.freakingawesome.net/2011/10/19/lazy-loading-by-using-c-yield-statements/)

      The shit I complain about It's like there ain't a cloud in the sky and it's raining out - Eminem ~! Firewall !~

      B 1 Reply Last reply
      0
      • B BillWoodruff

        Here's one way:

        // code here uses .NET 4.7

        // in a NameSpace
        public enum Divisions
        {
        Undefined,
        Admin,
        Finance,
        Sales,
        Research,
        IT,
        Temp
        }

        // in a Class: assume 'Person is a typical POCO
        public Dictionary>> DivisionToStaff { set; get; } =
        new Dictionary>>();

        // initialization : typically done in a 'ctor
        public Initialize()
        {
        foreach (Divisions div in Enum.GetValues(typeof(Divisions)))
        {
        DivisionToStaff.Add(div, new Lazy>());
        }
        }

        // sample use case:
        // DivisionToStaff[personInstance.Division].Value.Add(personInstance);

        Do you know a better way ? thanks, Bill

        «When I consider my brief span of life, swallowed up in an eternity before and after, the little space I fill, and even can see, engulfed in the infinite immensity of spaces of which I am ignorant, and which know me not, I am frightened, and am astonished at being here rather than there; for there is no reason why here rather than there, now rather than then.» Blaise Pascal

        Richard DeemingR Offline
        Richard DeemingR Offline
        Richard Deeming
        wrote on last edited by
        #3

        Not sure if it's better, but something like this might work:

        public class LazyDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>
        {
        private readonly ConcurrentDictionary<TKey, TValue> _values;
        private readonly Func<TKey, TValue> _valueFactory;
        private readonly Func<TKey, bool> _keyValidator;

        public LazyDictionary(Func<TKey, TValue> valueFactory, Func<TKey, bool> keyValidator = null, IEqualityComparer<TKey> keyComparer = null)
        {
            if (valueFactory == null) throw new ArgumentNullException(nameof(valueFactory));
            if (keyComparer == null) keyComparer = EqualityComparer<TKey>.Default;
            \_values = new ConcurrentDictionary<TKey, TValue>(keyComparer);
            \_valueFactory = valueFactory;
            \_keyValidator = keyValidator;
        }
        
        private bool KeyIsValid(TKey key) => \_keyValidator == null || \_keyValidator(key);
        
        private TValue GetOrAdd(TKey key) => \_values.GetOrAdd(key, \_valueFactory);
        
        public int Count => \_values.Count;
        
        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => \_values.GetEnumerator();
        
        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
        
        public IEnumerable<TKey> Keys => \_values.Keys;
        
        public IEnumerable<TValue> Values => \_values.Values;
        
        public bool ContainsKey(TKey key) => KeyIsValid(key);
        
        public bool TryGetValue(TKey key, out TValue value)
        {
            if (!ContainsKey(key))
            {
                value = default(TValue);
                return false;
            }
            
            value = GetOrAdd(key);
            return true;
        }
        
        public TValue this\[TKey key\]
        {
            get
            {
                if (!ContainsKey(key)) throw new KeyNotFoundException();
                return GetOrAdd(key);
            }
        }
        

        }

        Usage:

        public IReadOnlyDictionary<Division, IList<Person>> DivisionToStaff { get; }
        = new LazyDictionary<Division, IList<Person>>(d => new List<Person>(), d => Enum.IsDefined(typeof(Division), d));

        ...

        DivisionToStaff[personInstance.Division].Add(personInstance);

        ContainsKey will return true for any valid key. Count, GetEnumerator, and the Keys and Values properties will only reflect the keys which have already been created.

        "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

        B 1 Reply Last reply
        0
        • A Afzaal Ahmad Zeeshan

          I have never used Lazy loading in my own applications, for various reasons. Anyways, looking at your code, Bill, I can say if I had to implement "lazy" loading like feature here, I would simply just set it to null. In most cases of Lazy loading — for instance, the Entity Framework navigation — the types are null, unless you actually specify to need them. Then, once it is required, I would load the data using the yield operator; giving me somewhat relative of the lazy loading. But my answers depends on the way you fetch the List, from database perhaps? I have not yet tried .NET 4.7 by now. :( Does it include anything new? Shiv provides a good overview, and to rewrite that in a different way, would require the understanding that he provides here, [Can you explain Lazy Loading?](https://www.codeproject.com/Articles/652556/Can-you-explain-Lazy-Loading) [Lazy Loading By Using C# Yield Statements | Freaking Awesome](http://blog.freakingawesome.net/2011/10/19/lazy-loading-by-using-c-yield-statements/)

          The shit I complain about It's like there ain't a cloud in the sky and it's raining out - Eminem ~! Firewall !~

          B Offline
          B Offline
          BillWoodruff
          wrote on last edited by
          #4

          Quote:

          if I had to implement "lazy" loading like feature here, I would simply just set it to null

          Hi, Afzaal, I do not claim to be an expert on Lazy<T>: the question here comes out of my "quest" to better understand it. I would say that you use a Lazy<T> because instantiating one with 'new does not allocate memory for what it wraps. So you can eliminate guard-code like in the 'getter in this Property:

          // C# 7: using expression-body member as 'setter or 'getter now allowed in properties that are not read-only
          public List AllNodes
          {
          get => _allNodes ?? (_allNodes = new List());
          private set => _allNodes = value;
          }

          Even though I have not used the thread-safety features of Lazy<T>, it's clear those features are extensive. C# 7 ? : still trying to digest it :) Some well written articles by Jonathan Allen are helping: [^] cheers, Bill

          «When I consider my brief span of life, swallowed up in an eternity before and after, the little space I fill, and even can see, engulfed in the infinite immensity of spaces of which I am ignorant, and which know me not, I am frightened, and am astonished at being here rather than there; for there is no reason why here rather than there, now rather than then.» Blaise Pascal

          A 1 Reply Last reply
          0
          • Richard DeemingR Richard Deeming

            Not sure if it's better, but something like this might work:

            public class LazyDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>
            {
            private readonly ConcurrentDictionary<TKey, TValue> _values;
            private readonly Func<TKey, TValue> _valueFactory;
            private readonly Func<TKey, bool> _keyValidator;

            public LazyDictionary(Func<TKey, TValue> valueFactory, Func<TKey, bool> keyValidator = null, IEqualityComparer<TKey> keyComparer = null)
            {
                if (valueFactory == null) throw new ArgumentNullException(nameof(valueFactory));
                if (keyComparer == null) keyComparer = EqualityComparer<TKey>.Default;
                \_values = new ConcurrentDictionary<TKey, TValue>(keyComparer);
                \_valueFactory = valueFactory;
                \_keyValidator = keyValidator;
            }
            
            private bool KeyIsValid(TKey key) => \_keyValidator == null || \_keyValidator(key);
            
            private TValue GetOrAdd(TKey key) => \_values.GetOrAdd(key, \_valueFactory);
            
            public int Count => \_values.Count;
            
            public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => \_values.GetEnumerator();
            
            IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
            
            public IEnumerable<TKey> Keys => \_values.Keys;
            
            public IEnumerable<TValue> Values => \_values.Values;
            
            public bool ContainsKey(TKey key) => KeyIsValid(key);
            
            public bool TryGetValue(TKey key, out TValue value)
            {
                if (!ContainsKey(key))
                {
                    value = default(TValue);
                    return false;
                }
                
                value = GetOrAdd(key);
                return true;
            }
            
            public TValue this\[TKey key\]
            {
                get
                {
                    if (!ContainsKey(key)) throw new KeyNotFoundException();
                    return GetOrAdd(key);
                }
            }
            

            }

            Usage:

            public IReadOnlyDictionary<Division, IList<Person>> DivisionToStaff { get; }
            = new LazyDictionary<Division, IList<Person>>(d => new List<Person>(), d => Enum.IsDefined(typeof(Division), d));

            ...

            DivisionToStaff[personInstance.Division].Add(personInstance);

            ContainsKey will return true for any valid key. Count, GetEnumerator, and the Keys and Values properties will only reflect the keys which have already been created.

            B Offline
            B Offline
            BillWoodruff
            wrote on last edited by
            #5

            Wow ! That's the Ph.D. answer. My reading of the Lazy<T> docs suggests its multi-threading features are robust. thanks, Bill

            «When I consider my brief span of life, swallowed up in an eternity before and after, the little space I fill, and even can see, engulfed in the infinite immensity of spaces of which I am ignorant, and which know me not, I am frightened, and am astonished at being here rather than there; for there is no reason why here rather than there, now rather than then.» Blaise Pascal

            Richard DeemingR 1 Reply Last reply
            0
            • B BillWoodruff

              Quote:

              if I had to implement "lazy" loading like feature here, I would simply just set it to null

              Hi, Afzaal, I do not claim to be an expert on Lazy<T>: the question here comes out of my "quest" to better understand it. I would say that you use a Lazy<T> because instantiating one with 'new does not allocate memory for what it wraps. So you can eliminate guard-code like in the 'getter in this Property:

              // C# 7: using expression-body member as 'setter or 'getter now allowed in properties that are not read-only
              public List AllNodes
              {
              get => _allNodes ?? (_allNodes = new List());
              private set => _allNodes = value;
              }

              Even though I have not used the thread-safety features of Lazy<T>, it's clear those features are extensive. C# 7 ? : still trying to digest it :) Some well written articles by Jonathan Allen are helping: [^] cheers, Bill

              «When I consider my brief span of life, swallowed up in an eternity before and after, the little space I fill, and even can see, engulfed in the infinite immensity of spaces of which I am ignorant, and which know me not, I am frightened, and am astonished at being here rather than there; for there is no reason why here rather than there, now rather than then.» Blaise Pascal

              A Offline
              A Offline
              Afzaal Ahmad Zeeshan
              wrote on last edited by
              #6

              I have also not worked too much in this context because most of my data sources are SQL based databases, so I try to load only the data that I require,

              SELECT TOP 10 FROM table_name ...

              That works like a charm in my cases.

              BillWoodruff wrote:

              instantiating one with 'new does not allocate memory for what it wraps

              Of course, that is why I provided the Entity Framework example, they provide a function Include, which you execute and they then load the rest of the data, until then the objects are null. That EF code, gave me a hint that in most cases I should just leave the objects to null and then yield them when needed; this works in some cases. This yield does somewhat better, as it does provide the objects when we actually iterate over them (use them). As for C# 7, I just didn't get enough time to actually experiment around with them like [I did with C# 6](https://www.codeproject.com/Articles/1073905/Experimenting-with-Csharp-s-new-features), as I was busy with my final year project and some academics stuff. :-)

              The shit I complain about It's like there ain't a cloud in the sky and it's raining out - Eminem ~! Firewall !~

              1 Reply Last reply
              0
              • B BillWoodruff

                Wow ! That's the Ph.D. answer. My reading of the Lazy<T> docs suggests its multi-threading features are robust. thanks, Bill

                «When I consider my brief span of life, swallowed up in an eternity before and after, the little space I fill, and even can see, engulfed in the infinite immensity of spaces of which I am ignorant, and which know me not, I am frightened, and am astonished at being here rather than there; for there is no reason why here rather than there, now rather than then.» Blaise Pascal

                Richard DeemingR Offline
                Richard DeemingR Offline
                Richard Deeming
                wrote on last edited by
                #7

                The Lazy<T> threading support can be robust, depending on which LazyThreadSafetyMode value you pass to the constructor. (The default is ExecutionAndPublication, which is the most robust.) But the Dictionary<TKey, TValue> definitely isn't thread-safe if you modify it. It's not a problem if you're pre-populating the dictionary with a Lazy<T> for every possible key, and never modifying the contents of the dictionary. But if you have a large set of keys, some of which are rarely used, you might want to avoid the memory overhead.


                "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

                "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

                1 Reply Last reply
                0
                Reply
                • Reply as topic
                Log in to reply
                • Oldest to Newest
                • Newest to Oldest
                • Most Votes


                • Login

                • Don't have an account? Register

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • World
                • Users
                • Groups