What you will typically do is create a List<> of object references (pointers). So you can access the object through a reference, but the object is created in run-time.

Note that a List<> dynamically resizes/shrinks so you won't have to know in advance how many objects you need.

i.e.
Code:
List<TextBox> textboxes = new List<>();

fooA()
{
TextBox descBox = new TextBox();
this.Controls.Add(descBox);
textBoxes.Add(descBox);

Button addButton = new Button();
addButton.Click += new System.EventHandler(this.addButton_Clicked);
this.Controls.Add(addButton);
}

private void addButton_Clicked(object sender, EventArgs e)
{
      //some code
     textBoxes[10].Text = ....;
}
Note that if you want to associate a Button with a text you can do so as well. Then if button 10 is clicked then you can read the Text from the associated TextBox 10.

The way you manage the whole thing is up to you, there is always a way. The technique is to use a reference in the scope you want and instantiate objects wherever you want them to be created.

In my example above, you could delete a TextBox from the textBoxes list if you wanted and the object will be deleted (collected) as well.