Как создать тип, который является просто переменной, содержащей другой тип?

#c# #winforms

Вопрос:

Извините за мое очень плохо написанное название, я начинающий программист и только начал работать над приложением winforms на c#. В одной функции я создаю объект определенного типа, а затем в других функциях я перебираю список объектов этого типа, однако я переключаю тип используемого элемента управления, и когда я это делаю, мне нужно изменить объявление типа моего объекта более чем в двадцати местах. Есть ли способ создать переменную, содержащую этот тип, и определить все мои объекты с помощью этой переменной, чтобы мне нужно было указать тип только один раз, а затем изменить эту переменную. Поскольку я использую элементы управления winforms в качестве типов классов, все функции, которые я вызываю, одинаковы независимо от типа моих объектов, поэтому все, что мне нужно сделать, это изменить объявление типа, и все, извините, если это глупый вопрос, и любая помощь будет признательна.

Вот фрагмент моего кода для контекста:

 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.OfTypelt;ListViewgt;().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) {  Listlt;ListViewgt; list_of_groups = autolayoutGroups.Controls.OfTypelt;ListViewgt;().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 {  Listlt;ListViewgt; list_of_groups = autolayoutGroups.Controls.OfTypelt;ListViewgt;().ToList(); // a place where I need some type of placeholder   foreach (ListView l in list_of_groups)  {  // do something here  } }  

Комментарии:

1. Я переключаю тип управления, который я использую — как часто, реально?

2. Я не уверен, может быть, 4-5 раз до сих пор, плюс было бы неплохо знать на будущее, я помню какой-то урок программирования некоторое время назад о том, как, если вам нужно изменить одно и то же значение в нескольких местах, а затем заменить это значение переменной.

Ответ №1:

Если я правильно понимаю вашу проблему, в настоящее время у вас есть некоторый код, в котором вы используете ListView, и вам нужен тот же код, но вместо ListView вам нужен какой-то другой класс, например, DataGridView или поле со списком. Конечно, этот другой класс также должен иметь методы, которые вы использовали в представлении списка.

В C# это понятие называется общим. У вас есть универсальные классы и универсальные методы.

Вы определяете универсальный тип, вводя идентификатор вместо детали, которую хотите заменить другим типом.

В вашем случае: вы хотите заменить ListView на DataGridView. В функции 1 вы создаете представление списка и задаете некоторые свойства. Сначала мы поместим это создание в отдельный метод, у вас будет что-то вроде этого:

 private ListView CreateListView() {  ListView listview = new ListView();  int count2 = autolayoutGroups.Controls.OfTypelt;ListViewgt;().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 }  

(Небольшая оптимизация, выходит за рамки вопроса): чтобы вычислить количество 2, не создавайте список всех просмотров списков, а затем подсчитывайте их; используйте Count() на IEnumerablelt;ListViewgt; .

Чтобы изменить CreateListView таким образом, чтобы он мог создавать что-либо типа TMyType, определите универсальный метод следующим образом:

 private TMyType Createlt;TMyTypegt;() {  TMyType createdObject = new TMyType();  int count2 = autolayoutGroups.Controls  .OfTypelt;TMyTypegt;()  .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 ; }  

Поэтому все, что я сделал , это то , что всякий раз, когда я сохранял ListView , я заменял его TMyType типом, который должен быть создан.

Использование:

 ListView createdListView = this.Createlt;ListViewgt;(); DataGridView createdDataGridView = this.Createlt;DataGridViewgt;(); ComboBox createdComboBox = this.Createlt;ComboBoxgt;();  

Есть только одна проблема. Вам придется сообщить компилятору, что у TMyType есть конструктор по умолчанию (который вы хотите сделать new TMyControl() ), и у него есть такие методы, как Size , BackColor , ForeColor и т. Д.

Если TMyType будет производным от класса Control , то вы будете уверены, что у него есть нужный конструктор и он знает все методы, которые вам нужно использовать.

Чтобы сказать, что универсальный тип является производным от определенного типа, вы используете следующую структуру:

 private TMyType Createlt;TMyTypegt;() where TMyType: Control {  // because you are certain the TMyType is derived from Control  // you can use all methods of class Control  }  

Это ответ на ваш вопрос: создайте универсальный метод

Некоторые другие вещи о дженериках

Другой пример: Если вы хотите сообщить компилятору, что универсальный тип реализует IComparable :

 private T Processlt;Tgt;(T input) where T: IComparable {...}  

Или несколько:

 private T Processlt;Tgt;(T input) where T: IComparable, IEquatable {...}  

И, наконец, если вы хотите, чтобы универсальный тип имел конструктор по умолчанию:

 private T Processlt;Tgt; () where T: new  

Ответ №2:

На самом деле не совсем ясно, какова цель, но я полагаю, что вы можете создать свойство, которое возвращает ваш часто используемый список:

 private Listlt;ListViewgt; AutolayoutGroupControls =gt;   autolayoutGroups.Controls.OfTypelt;ListViewgt;().ToList()  

Тогда вы сможете

 foreach(var lv in AutolayoutGroupControls)}  ... }  

Но это мало что дает; если вы измените эту опору, чтобы вернуть что-то еще, вам все равно придется внести кучу изменений. Если ваши циклы всегда делают одно и то же, поместите его в метод и вызовите его из N обработчиков событий