【问题标题】:How to create a type that Is just a variable containing another type?如何创建一个只是包含另一种类型的变量的类型?
【发布时间】:2021-11-23 20:34:56
【问题描述】:

对不起,我写得很糟糕的标题,我是一个初学者程序员,我刚开始使用 c# winforms 应用程序。在一个函数中,我创建了某种类型的对象,然后在其他函数中,我遍历了该类型对象的列表,但是我正在切换我正在使用的控件类型,当我这样做时,我必须更改类型在二十多个地方声明我的目标。有没有办法创建一个保存该类型的变量,而不是定义该变量的所有对象,所以我只需指定一次类型,然后更改该变量。因为我使用 winforms 控件作为我的类类型,所以无论我的对象是什么类型,我调用的所有函数都是相同的,所以我需要做的就是更改类型声明,仅此而已,对不起,如果这是一个愚蠢的问题任何帮助将不胜感激。

这是我的上下文代码的 sn-p:

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
   }
}

【问题讨论】:

  • 我正在切换我正在使用的控件类型 - 多久一次?
  • 我不确定,到目前为止可能有 4-5 次,而且很高兴知道未来,我记得不久前的一些编程课,如果你必须更改相同的值然后在几个地方用变量替换该值。

标签: c# winforms


【解决方案1】:

如果我正确理解您的问题,您目前有一些使用 ListView 的代码,并且您想要相同的代码,但您需要其他类而不是 ListView,例如 DataGridView 或 ComboBox。当然,这个其他类也必须具有您在 ListView 上使用的方法。

在 C# 中,这个概念被称为泛型。你有泛型类和泛型方法。

您通过键入一个标识符而不是您想用另一种类型替换的部分来定义泛型。

在您的情况下:您想用 DataGridView 替换 ListView。在 function1 中,您创建一个 ListView,并设置一些属性。首先我们将这个创建放在一个单独的方法中,你会得到这样的:

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
}

(小优化,超出问题范围):计算count2,不要创建所有ListView的List,然后Count它们;在IEnumerable&lt;ListView&gt; 上使用Count()

要更改 CreateListView 使其可以创建 TMyType 类型的任何内容,请像这样定义泛型方法:

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 ;
}

所以我所做的就是,每当我保存 ListView 时,我将其替换为应该创建的类型 TMyType

用法:

ListView createdListView = this.Create<ListView>();
DataGridView createdDataGridView = this.Create<DataGridView>();
ComboBox createdComboBox = this.Create<ComboBox>();

只有一个问题。你必须告诉编译器 TMyType 有一个默认构造函数(你想做new TMyControl()),它有SizeBackColorForeColor等方法。

如果 TMyType 是从Control 派生的类,那么您可以确定它具有所需的构造函数并且知道您需要使用的所有方法。

要说泛型类型是从某个类型派生的,你可以使用以下结构:

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  
}

这回答了你的问题:创建一个泛型方法

关于泛型的其他一些事情

另一个例子:如果你想告诉编译器泛型类型实现了IComparable

private T Process<T>(T input) where T: IComparable {...}

或多个:

private T Process<T>(T input) where T: IComparable, IEquatable {...}

最后,如果你想要求泛型类型有一个默认构造函数:

private T Process<T> () where T: new

【讨论】:

    【解决方案2】:

    目前还不清楚目标是什么,但我想你可以创建一个返回常用列表的属性:

    private List<ListView> AutolayoutGroupControls => 
      autolayoutGroups.Controls.OfType<ListView>().ToList()
    

    那你就可以了

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

    但它提供的并不多;如果您更改该道具以返回其他内容,您仍然需要进行大量更改。如果你的循环总是做同样的事情,把它放到一个方法中并从 N 个事件处理程序中调用它

    【讨论】:

      猜你喜欢
      • 2018-11-27
      • 1970-01-01
      • 2014-01-21
      • 2021-12-26
      • 1970-01-01
      • 1970-01-01
      • 2018-06-12
      • 2021-07-27
      • 1970-01-01
      相关资源
      最近更新 更多