4

我认为自己是一名优秀的中级 .Net 开发人员,在过去 3 年多的时间里,我对 C# 中的所有概念和术语都有了不错的理解。但是,我有一个问题,如果它看起来像一个愚蠢而愚蠢的问题,我深表歉意。我想知道的是为什么框架类库中的某些方法在更广泛的数据类型更有意义时返回窄数据类型,我们必须稍后将其转换为我们感兴趣的数据类型。我想给出以下两个例子来支持我的问题:

  1. Label Label1 = (Label)Grid.FindControl("Label1");
    在这个例子中,为什么 FindControl 返回一个 Control 类型的实例,我们必须将它转换为 Label 类型。它可能返回了一个 Label 类型的实例,因为我们传递了一个在方法参数的标记中声明的有效 ID。

  2. protected override object SaveViewState()
    在此示例中,返回 on 对象,我们必须将其强制转换为字符串类型。

如果我的问题令人困惑,我再次抱歉。我只想知道为什么这些场景在返回窄类型时会返回更宽的类型,并且它可以避免我们额外的转换为我们想要的类型的步骤。

4

4 回答 4

5

这是因为当您设计一个框架时,您需要尽可能在一般级别上进行操作,或者如果您愿意,可以在抽象级别上进行操作。返回最可能的基类,在这种情况下,它创建了一个几乎可以支持任何东西的抽象。想象:

Label     label1 = (Label)Grid.FindControl("Label1"); 
TextBox   textBox1 = (TextBox)Grid.FindControl("TextBox1"); 
Calendar  calendar1= (Grid)Grid.FindControl("Calendar1"); 

只有一种方法可以Grid. 调用者知道它到底是什么,所以转换为已知类型。

如果我像一个框架设计师一样,想为 , , 制作特殊的方法LabelTextBoxCalendar需要为每种类型添加一个方法。我想你会同意,从框架设计者的角度来看,这简直是不可想象的。从应该为其他开发人员设计通用基础架构的开发人员的角度来看。

于 2012-09-06T20:35:03.050 回答
5

首先,您有点转过身来,因为“更宽”通常用于派生较少的类型。例如Control比 更广泛,Label因为该定义涵盖了从 派生的所有内容Control,其中包括Label以及其他事物。

至于实际问题。有时人们可以争论例如一个方法的利弊,该方法返回的实际上是List<T>返回它的List<T>orIList<T>ICollection<T>or IEnumerable<T>。我们可以将一些好的原则应用于该决定,但是在尽可能广泛地保持有用和尽可能地缩小范围仍然有优势。

但这并不适用于此。除非将其定义为仅返回标签,否则无法Control.FindControl()返回。Label这不是它的用途,它是用于返回任何类型的控件,因此结果可能很容易成为中继器或网格。

您自己说SaveViewState,“转换为可能是字符串类型。” 答案就在那个“也许”中。当然它可能是一个字符串,但它可能是一个object[]或一个List<string>或一个Dictionary<string, string>

如果是你写的程序员SaveViewState,你会如何定义它?您必须涵盖所有这些可能性以及更多,因此您必须将其定义为返回object

于 2012-09-06T20:40:26.483 回答
3

在标记文件中定义这一事实ID并不意味着在编译时该类型是已知的,更糟糕​​的是,根本没有办法验证这一点,因为标记文件不是编译过程的一部分。

单独使用标识符也不太可能做这样的事情string,因为 C# 中的返回类型不支持协变(你不能有一个调用的方法FindControl同时返回LabelControl)。

您可以从中获得的最接近的东西是让 IDE 生成一个扩展方法FindLabel1,然后为您进行强制转换,但这就像您的代码一样只是一个 hack,它不能保证任何事情。

于 2012-09-06T20:36:26.443 回答
3

Label Label1 = (Label)Grid.FindControl("Label1");

在这个例子中,为什么 FindControl 返回一个 Control 类型的实例,我们必须将它转换为 Label 类型。

你错了。方法返回类型Control,但返回的实例类型Label(否则您将无法向上转换它)。

它可能返回了一个 Label 类型的实例,因为我们传递了一个在方法参数的标记中声明的有效 ID。

可以而且确实可以。但是您在这里真正要问的是“为什么我需要向上转型”。因为方法返回类型被声明为Control是因为在编译时,当变量类型被解析时,根本无法知道你的控件类型。

于 2012-09-06T20:37:07.687 回答