title: Handling large number of Tasks in C#
body: <p>I have a BindingList&lt;> of objects bound to a DataGridView. These objects contain a foreign key for another object, and some of the columns of the first object are meant to show a read-only field from the foreign key object.</p>
  
  <p>I thought I could keep a copy of the foreign object as a private variable, and if this was null, I would make a fetch request to the webservice to obtain the foreign object, then call NotifyPropertyChanged() on the relevant fields to indicate that the foreign object has been loaded and to update those fields in the DataGridView.</p>
  
  <p>This works -- to a point. For large numbers of records, it seems some tasks run and never return, even when cancelled. Is there a better way of doing this?</p>
  
  <pre><code>    private ForeignObj _foreignObject = null;
      public string ForeignName
      {
          get
          {
              if (!_foreignKey.HasValue)
                  return null;
  
              if (_foreignObject == null)
              {
                  GetForeignObject(); // method is async, so it spawns a task and returns immediately
                  return "Fetching...";
              }
  
              return _foreignObject.Name;
          }
      }
  
      CancellationTokenSource foreignObjectToken = null;
      public async Task GetForeignObject()
      {
          if (foreignObjectToken != null)
              return; // Don't call it again while it is already fetching
  
          foreignObjectToken = new CancellationTokenSource();
          foreignObjectToken.CancelAfter(10000); // Don't let request go longer than 10 seconds
  
          _foreignObject = await DTOPropertyHelper.GetForeignObject(_foreignKey.Value, foreignObjectToken.Token); // HTTP request to web service to obtain foreign object
  
          OnPropertyChanged("ForeignName");
          foreignObjectToken = null;
      }
  </code></pre>
  
  <p>Update: I find that this 'works' in the property getter, but is ugly:</p>
  
  <pre><code>get
  {
      if (!_foreignKey.HasValue)
          return null;
  
      if (_foreignObject == null)
      {
          if (DTOPropertyHelper.NumTasks &lt; DTOPropertyHelper.MaxTasks)
              GetForeignObject();
          else
              OnPropertyChanged("ForeignName");
  
          return null;
      }
  
      return _foreignObject.Name;
  }
  </code></pre>
  
  <p>...Essentially constantly firing a PropertyChanged event which continues to hammer the task creation providing less than the MaxTasks number is valid (DTOPropertyHelper.GetForeignObject() automatically increments and decrements NumTasks).</p>