Sorry for my verry badly written title, I'm a beginner programmer and I just started on a c# winforms app. In one function I create an object of some type and then in other functions I iterate through a list of that type of objects, however I'm switching the type of control I'm using and when I do, I have to change the type declaration of my object in over twenty places. Is there a way to create a variable that holds that type and than define all my objects off that variable so I only have to specify the type once and then change that variable. Because I'm using winforms controls as my class types all the functions I call are all then same no matter what type my objects are, so all I need to do is change the type declaration and that's it, sorry if this is a stupid question and any help would be appreciated.
Here is a snippet of my code for context:
private void function1(object sender, EventArgs e) //not my actual function because the real function has lots of other unrelated code
{
ListView PlaceType = new ListView(); // these ListView types i would like to replace with a placeholder if possible
ListView listview = new ListView();
int count2 = autolayoutGroups.Controls.OfType<ListView>().ToList().Count();
listview.Size = new System.Drawing.Size(150, 100);
listview.BackColor = normalColor;
listview.BorderStyle = BorderStyle.Fixed3D;
listview.ForeColor = System.Drawing.Color.Black;
listview.Name = "Group" count2;
listview.MouseDown = Select;
}
private void function2(object sender, EventArgs e)
{
List<ListView> list_of_groups = autolayoutGroups.Controls.OfType<ListView>().ToList(); // a place where I need some type of placeholder
foreach (ListView l in list_of_groups)
{
// do something here
}
}
private void function3(object sender, EventArgs e) // I have several functions like this
//and if I change the control I'm using I have to change the types in every function
{
List<ListView> list_of_groups = autolayoutGroups.Controls.OfType<ListView>().ToList(); // a place where I need some type of placeholder
foreach (ListView l in list_of_groups)
{
// do something here
}
}
CodePudding user response:
If I understand your problem correctly, you currently have some code where you use a ListView, and you want the same code, but instead of ListView you want some other class, for instance a DataGridView, or a ComboBox. Of course this other class must also have the methods that you used on the ListView.
In C# this concept is called a generic. You have generic classes and generic methods.
You define the generic by typing an identifier instead of the part that you want to replace with another type.
In your case: you want to replace ListView by DataGridView. In function1 you create a ListView, and set some properties. First we'll put this creation in a separate method, you will have something like this:
private ListView CreateListView()
{
ListView listview = new ListView();
int count2 = autolayoutGroups.Controls.OfType<ListView>().Count();
listview.Size = new System.Drawing.Size(150, 100);
listview.BackColor = normalColor;
listview.BorderStyle = BorderStyle.Fixed3D;
listview.ForeColor = System.Drawing.Color.Black;
listview.Name = "Group" count2;
listview.MouseDown = Select;
return listView;
}
private void function1(object sender, EventArgs e)
{
ListView createdListView = this.CreateListView();
// TODO: do something with the created ListView
}
(Small optimization, out of scope of the question): to calculate count2, don't create a List of all ListViews, and then Count them; use Count()
on the IEnumerable<ListView>
.
To change CreateListView such that it can create anything of type TMyType, define the generic method like this:
private TMyType Create<TMyType>()
{
TMyType createdObject = new TMyType();
int count2 = autolayoutGroups.Controls
.OfType<TMyType>()
.Count();
createdObject.Size = new System.Drawing.Size(150, 100);
createdObject.BackColor = normalColor;
createdObject.BorderStyle = BorderStyle.Fixed3D;
createdObject.ForeColor = System.Drawing.Color.Black;
createdObject.Name = "Group" count2;
createdObject.MouseDown = Select;
return createdObject ;
}
So all I did was, that whenever I save ListView
, I replaced it with TMyType
, the type that should be created.
Usage:
ListView createdListView = this.Create<ListView>();
DataGridView createdDataGridView = this.Create<DataGridView>();
ComboBox createdComboBox = this.Create<ComboBox>();
There is only one problem. You'll have to tell the compiler that TMyType has a default constructor (you want to do new TMyControl()
), and that is has methods like Size
, BackColor
, ForeColor
, etc.
If TMyType would be a class derived from Control
, then you would be certain that it has the desired constructor and knows all methods that you need to use.
To say that a generic type is derived from a certain type, you use the following structure:
private TMyType Create<TMyType>() where TMyType: Control
{
// because you are certain the TMyType is derived from Control
// you can use all methods of class Control
}
This answers your question: create a generic method
Some other things about generics
Another example: If you want to inform the compiler that the generic type implements IComparable
:
private T Process<T>(T input) where T: IComparable {...}
Or multiple:
private T Process<T>(T input) where T: IComparable, IEquatable {...}
And finally if you want to require that the generic type has a default constructor:
private T Process<T> () where T: new
CodePudding user response:
It's not really clear what the goal is but I suppose you can make a property that returns your commonly used list:
private List<ListView> AutolayoutGroupControls =>
autolayoutGroups.Controls.OfType<ListView>().ToList()
Then you can
foreach(var lv in AutolayoutGroupControls)}
...
}
But it doesn't offer much; if you change that prop to return something else you still have a stack of changes to make. If your loops always do the same thing put it into a method and call it from N event handlers