Recently I started my steps with C # and I have been reading about method overload. I have the following code as a method extension within a class that I named Utilities:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Classes
{
public static class Utilities
{
public static IEnumerable<Control> GetAllChildren(this Control parent)
{
Stack<Control> stack = new Stack<Control>();
stack.Push(parent);
while (stack.Any())
{
var next = stack.Pop();
foreach (Control child in next.Controls)
{
stack.Push(child);
}
yield return next;
}
}
}
This method allows me to obtain all controls within a specific control. Amazing! I can make a call to this method as follows:
private void Button1_Click(object sender, EventArgs e)
{
foreach (Control control in TabControl.SelectedTab.GetAllChildren())
{
MessageBox.Show(control.Name);
}
}
and as I expected ... I can go through each of the controls within a specific control. (In this case ... TabControl)
My question is this: How can I make this method a method overload?, so that I accept as a first argument a List of several controls, and execute this same method on each of them and return it as a single collection that can iterate
Example: I want to do something similar to the following:
private void ButtonSave_Click(object sender, EventArgs e)
{
List<Control> controls = new List<Control> {
TabControl1,
TabControl2
};
foreach (Control control in controls.GetAllChildren())
{
MessageBox.Show(control.Name);
}
}
Please, I would appreciate any help .. Thank you very much in advance
EDIT 1:
In my Utilities Class I have created a new method with the same name and the class looks like this, but I don't know how to write the logic of that method to perform the action I expect ...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace BASCAL.Classes
{
public static class Utilities
{
public static IEnumerable<Control> GetAllChildren(this Control parent)
{
Stack<Control> stack = new Stack<Control>();
stack.Push(parent);
while (stack.Any())
{
var next = stack.Pop();
foreach (Control child in next.Controls)
{
stack.Push(child);
}
yield return next;
}
}
public static IEnumerable<Control> GetAllChildren(this List<Control> parents)
{
if (parents.Any())
{
// Logic goes here!
}
}
}
}
This can be pretty straight forward, and you can reuse your existing logic for convenience. You'll want to declare another extension method that accepts an IEnumerable<Control>
instead of just a control.
You'll then get the controls for each control in the list, which will result in a list of lists. You then want to flatten that into a single list of Control
. You can accomplish that with LINQ's SelectMany
.
The following should work:
public static IEnumerable<Control> GetAllChildren(this IEnumerable<Control> controls) => controls.SelectMany(GetAllChildren);
Alongside your original definition of GetAllChildren
, you now have an overloaded method. One accepts a single Control
as it's parameter, the other accepts an IEnumerable<Control>
as it's parameter.
public static IEnumerable<Control> GetAllChildren(this IEnumerable<Control> parents)
{
return parents.SelectMany(p => p.GetAllChildren());
}
Add another extension that accepts a collection of controls.
You can reuse the existing extension method for each control in the list, and use LINQ SelectMany
to combine the children into a single collection.
While your original method's signature is
public static IEnumerable<Control> GetAllChildren(this Control parent)
the signature of should be
public static IEnumerable<Control> GetAllChildren(this IEnumerable<Control> parents)
I made up an example with integer nubmbers:
struct Foo
{
public int[] parts;
}
void Main()
{
Foo f1 = new Foo() { parts = new int[] {3, 6, 9}};
Foo f2 = new Foo() { parts = new int[] {4, 40, 400, 4000}};
Foo f3 = new Foo() { parts = new int[] {3, 33, 333}};
var fooList = new List<Foo>() { f2, f3 };
foreach (var element in tellFoo(f1))
Console.WriteLine(element);
foreach (var element in tellFoo(fooList))
Console.WriteLine(element);
}
IEnumerable<int> tellFoo(Foo x)
{
foreach (var element in x.parts)
yield return element;
}
IEnumerable<int> tellFoo(IEnumerable<Foo> foos)
{
foreach (var foo in foos)
foreach (var element in tellFoo(foo))
yield return element;
}
So we have two overloads that both return one element at a time. The second one uses the first.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.