‘as`和`is`的真正用途

我曾经使用或者使用C#或任何支持该关键字的语言。

你用它做什么用的?

我不是说我如何使用它我的意思是你真的需要它?

我也在一个相当大的c ++项目中没有进行类型转换(我很自豪)。

所以考虑到我几乎从不打字,为什么我需要关键字as或是?

我必须编写代码来枚举放置在ASP.NET webform上的所有控件,并对特定控件执行某些操作,例如为所有Textbox添加背景颜色,等等。

asis对我来说的主要好处是我可以安全地检查变量是否属于给定类型is而不会发生exception。 一旦我确定它属于给定类型,我就可以安全轻松地将其转换为使用as所需的类型。

我基本上做了什么(简化!)是一个

 foreach(Control c in form.Controls) { if(c is Textbox) HandleTextbox(c as Textbox); if(c is Listbox) HandleListbox(c as Listbox); } 

等等。 没有as并且这将是一个很麻烦,恕我直言。

基本上,你可能需要或者可以很好地利用as ,如果你正在处理多态性 – 如果你有可以是任意数量的类型的列表,比如我的例子中页面上的控件。 如果您没有或不使用多态,那么您不太可能遇到对这些运算符的需求。

我在事件处理程序中使用’as’作为一个方便的快捷方式,以便在设计时无法知道发送方时将发送对象恢复。

 protected void SomeButtonInAGridView_Click(object sender, EventArgs e) { Button clickedButton = sender as Button; } 

这是一个很多出现的:

 class Foo { public override bool Equals(object obj) { // The more specific function needs to do null checking anyway. return Equals(obj as Foo); } public bool Equals(Foo obj) { // do some comparison here. } } 

有趣的问题。 实际上,我一直都在使用它们。 is很方便地找出一个对象是否属于某种类型,我偶尔会在generics或循环中使用不同类型的对象。 它对reflection也很有价值。

另一个,发现了更多的用途。 使用正常转换通常更安全:当它失败时,它返回null,而不是exception。 我也发现它更清晰,更容易使用它,检查null的返回值,然后添加一个exception块。

基本上,我的意思是,我更喜欢这个:

 protected void GeneralEventHandler(object sender, EventArgs e) { Button btn = sender as Button; if(btn != null) // click came from a button! // do something else // other cases } 

还有这个:

 protected void GeneralEventHandler(object sender, EventArgs e) { if(sender is Button) // click came from a button! // do something else // other cases } 

与此相反:

 protected void GeneralEventHandler(object sender, EventArgs e) { try { Button btn = (Button) sender; // if we get this far, it's a button } catch(InvalidCastException ice) { // click did not come from a button! Handle other cases } } 

当然,这只是一个例子,但是当我可以避免尝试/捕获时,我会。 这也为真正的例外提供了更多的空间。

我用它来干净地从可能是DBNullDataReader获取数据。

 int? personHeight = dr["Height"] as int?; 

要么

 int personHeight = dr["Height"] as int? ?? 0; 

以下是Eric Lippert的一篇文章,描述了如何在C#中使用“as”:

http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx

我一直都在使用。 当我必须从会话缓存中拉回一个序列化对象时,我用它来确定序列化对象是否存在并且类型正确。 我可以避免程序抛出错误,使用as运算符并检查null。 如果它为null,我知道缺少某些东西,我可以重新创建该对象,并在下次需要时将其推回缓存。

您可以使用强制转换运算符完成相同的结果,但这会增加exception的开销,尤其是当您知道序列化对象不会在某些时间出现时。

C#提供了使用is和as运算符进行转换的方法。 is运算符检查对象是否与给定类型兼容,并且评估结果是布尔值:true或false。 is运算符永远不会抛出exception。 以下代码演示:

 System.Object o = new System.Object(); System.Boolean b1 = (o is System.Object); // b1 is true. System.Boolean b2 = (o is Employee); // b2 is false. 

如果对象引用为null,则is运算符始终返回false,因为没有可用于检查其类型的对象。

is运算符通常如下使用:

 if (o is Employee) { Employee e = (Employee) o; // Use e within the 'if' statement. } 

在此代码中,CLR实际上是两次检查对象的类型:is运算符首先检查o是否与Employee类型兼容。 如果是,则在if语句内部,CLR再次validationo在执行转换时o引用Employee。

C#提供了一种简化此代码并通过提供as运算符来提高其性能的方法:

 Employee e = o as Employee; if (e != null) { // Use e within the 'if' statement. } 

在此代码中,CLR检查o是否与Employee类型兼容,如果是,则返回指向同一对象的非null指针。 如果o与Employee类型不兼容,则as运算符返回null。

如果你开发了一个提供插件界面的项目,那么很快就会成为你最好的朋友。

这是进入Caligari博士内阁的另一个用例;-)

您可以链接as运算符,如:

 x = obj as Label as Control; 

你为什么要做这样的事情? 如果你想要null,如果它不是Label,但你想将它们全部视为Control。 只需将Textbox和Label直接转换为Control就可以为两者带来成功,现在对于不需要的Control类型它将为null。 这是一种您不需要经常使用的快捷方法,但偶尔也很方便。

另一种用途是在对象上需要ToString()时,但只有当它具有正确的类型时,否则您需要一个默认字符串。 这是我经常遇到的情况,尤其是。 与POCO。 因为ToString()是虚拟的,所以这适用:

 // assume SomeClass has overridden ToString() // return "none" if item is not of type SomeClass or if it is null to begin with string itemText = (item as SomeClass as Object ?? "none").ToString(); 

如果InvalidCastException失败,C风格的强制转换(如(Foo)bar )将抛出InvalidCastException 。 另一方面, as将产生null (见此)。 is运算符仅用于测试给定实例的运行时类型是否与提供的类型兼容(请参阅此 )。

is在.NET System.ComponentModel命名空间中广泛使用的。 更具体地说, TypeConverter API在很大程度上依赖于is运算符来确定如何从一种类型转换为另一种类型。

我在WinForms应用程序中广泛使用了这两个关键字,其中有一个用于编辑发票的GUI, ListView每一行都可以包含不同类型的项目(即,它可以是行项目或描述,或者……)。 我放在ListView中的所有项都是从ListViewItem派生的,所以稍后当我去实现编辑所选项时,我必须检查选择了哪个项类型(使用is )来显示相应的编辑GUI。

自定义TypeConverters首先考虑。

 public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) { if (value is string) { return GetEnumValue(myVal, (string)value); } if (value is Enum) { return GetEnumDescription((Enum)value); } return base.ConvertFrom(context, culture, value); } 

第二个来自我有一个对象的阴影(用于跟踪更改)从一个基类inheritance的情况

 class BaseClass { BaseClass _shadow; } protected override void UpdateShadow() { ThisClass shadow = _shadow as ThisClass; //... } 

如果你真的从来没有做过铸造那么我可能对这些操作员没什么用处。 但是,根据我的经验,.NET编程需要进行大量的转换,特别是在处理提供类型为“object”的参数的委托时。 我认为引入仿制药有助于减少对铸造的需求,但这肯定是我经常使用的东西。 我可能“做错了”但这只是我的经历。

因此,如果您要进行转换,我真的很喜欢’is’运算符,以提高代码的可读性。 我更愿意看

 if(foo is SomeType) {...} 

然后

 if(foo.GetType() == typeof(SomeType)) {...} 

marc_s的答案有点瑕疵,我一直看到这段代码所以我想强调这些运算符之间差异的重要性。 is是一个布尔测试,用于确定对象是否可分配给某个类型。 检查一个对象是否可以分配给某个类型,如果是,则返回该对象作为该类型,如果不是,则返回null。 marc_s的回答是这样做的

 foreach(Control c in form.Controls) { if(c is Textbox) HandleTextbox(c is Textbox ? (Textbox)c : null); if(c is Listbox) HandleListbox(c is Listbox ? (Listbox)c : null); } 

as一起使用是多余的。 当你使用as只是用上面的表达式替换它时,它是等价的。 使用直接强制转换()或仅用于自身。 写这个例子的更好方法是。

 foreach(Control c in form.Controls) { if(c is Textbox) HandleTextbox((Textbox)c); //c is always guaranteed to be a Textbox here because of is if(c is Listbox) HandleListbox((Listbox)c); //c is always guaranteed to be a Listbox here because of is } 

或者,如果你真的喜欢

 foreach(Control c in form.Controls) { var textBox = c as Textbox; if(textBox != null) { HandleTextbox(textBox); continue; } var listBox = c as ListBox if(listBox != null) HandleListbox(listBox); } 

我一直遇到的一个真实世界的例子是从只返回类型对象的存储区域获取对象。 缓存就是一个很好的例子。

 Person p; if (Cache[key] is Person) p = (Person)Cache[key]; else p = new Person(); 

我在实际代码中使用的更少,因为它实际上只适用于引用类型。 请考虑以下代码

 int x = o as int; if (x != null) ??? 

因为int不能为null as失败。 is工作得很好

 int x; if (o is int) x = (int)o; 

我确信这些运算符之间也存在一些速度差异,但对于实际应用,差异可以忽略不计。