【问题标题】:When should you use the as keyword in C#什么时候应该在 C# 中使用 as 关键字
【发布时间】:2011-09-27 08:29:34
【问题描述】:

当您大部分时间想要更改类型时,您只想使用传统的演员表。

var value = (string)dictionary[key];

很好,因为:

  • 很快
  • 如果有问题,它会抱怨(而不是给 object is null 异常)

那么使用as 的好例子是什么?

注意:实际上我认为有时编译器会阻止使用 as 起作用的类型转换(与泛型相关?)。

【问题讨论】:

  • 编译器并没有真正“阻止”强制转换,它只是在它可以静态确定类型不相关时给出错误,因此强制转换总是会失败。
  • is 模式匹配可能是当今更现代的方式。

标签: c# .net c#-3.0 as-operator


【解决方案1】:

as有效 时使用as,因为对象不是您想要的类型,并且如果它是您想要采取不同的行动。例如,在一些伪代码中:

foreach (Control control in foo)
{
    // Do something with every control...

    ContainerControl container = control as ContainerControl;
    if (container != null)
    {
        ApplyToChildren(container);
    }
}

或者优化LINQ to Objects(很多这样的例子):

public static int Count<T>(this IEnumerable<T> source)
{
    IList list = source as IList;
    if (list != null)
    {
        return list.Count;
    }
    IList<T> genericList = source as IList<T>;
    if (genericList != null)
    {
        return genericList.Count;
    }

    // Okay, we'll do things the slow way...
    int result = 0;
    using (var iterator = source.GetEnumerator())
    {
        while (iterator.MoveNext())
        {
            result++;
        }
    }
    return result;
}

所以使用as 就像一个is + 一个演员表。根据上面的示例,它几乎总是与之后的无效性检查一起使用。

【讨论】:

  • 语义上“就像一个 is + a cast”。从 IL 看,这当然是正确的,有趣的是,事实并非如此(我相信你知道,但不是所有人都知道你的答案)blogs.msdn.com/b/ericlippert/archive/2010/09/16/…
  • 你有“几乎总是”的例子吗?
  • @Lavinski:我偶尔将as 与参数可以为空的方法调用一起使用,因此我能够无条件地传递它。不过,该方法中可能有一个空检查:) 一种变体是将它与空合并运算符一起使用,例如IList&lt;T&gt; list = sequence as IList&lt;T&gt; ?? sequence.ToList();
【解决方案2】:

每当您需要安全地投射对象时,请使用as

MyType a = (MyType)myObj; // throws an exception if type wrong

MyType a = myObj as MyType; // return null if type wrong

【讨论】:

  • 我会说 OP 首先要求何时使用安全演员
  • 是的,我回答:当您需要安全地投射对象时
  • @Saminch 我的意思是你没有回答“你什么时候需要一个安全的演员”这个问题。 (一个安全的演员从一开始就不会抛出)。因此,答案将包括一个场景,其中对象为不同类型是有效的,但如果您能够使用运行时类型的知识,您可能会有所收获。有关示例,请参见 Jons 的答案
  • 同意使用示例在这里会更有帮助。你可以投反对票。
  • 我觉得没有必要投反对票。你的答案没有错。我只是建议一种让它变得更好的方法(恕我直言)
【解决方案3】:

As 用于避免双重转换逻辑,如:

if (x is MyClass)
{
  MyClass y = (MyClass)x;
}

使用

MyClass y = x as MyClass;
if (y == null)
{
}

仅供参考,IL 为案例 #1 生成:

  // if (x is MyClass)
  IL_0008:  isinst     MyClass
  IL_000d:  ldnull
  IL_000e:  cgt.un
  IL_0010:  ldc.i4.0
  IL_0011:  ceq
  IL_0013:  stloc.2
  IL_0014:  ldloc.2
  IL_0015:  brtrue.s   IL_0020
  IL_0017:  nop
  // MyClass y = (MyClass)x;
  IL_0018:  ldloc.0
  IL_0019:  castclass  MyClass
  IL_001e:  stloc.1

对于案例 #2:

  // MyClass y = x as MyClass;
  IL_0008:  isinst     MyClass
  IL_000d:  stloc.1
  // if (y == null)
  IL_000e:  ldloc.1
  IL_000f:  ldnull
  IL_0010:  ceq
  IL_0012:  stloc.2
  IL_0013:  ldloc.2
  IL_0014:  brtrue.s   IL_0018

【讨论】:

    【解决方案4】:

    使用as 不会抛出转换异常,如果转换失败,只会返回null

    【讨论】:

      【解决方案5】:

      .Count() 在 Enumerable 中的实现使用它来使 Count() 用于收集更快

      实现是这样的:

              ICollection<TSource> collection = source as ICollection<TSource>;
              if (collection != null)
              {
                  return collection.Count;
              }
              ICollection collection2 = source as ICollection;
              if (collection2 != null)
              {
                  return collection2.Count;
              }
      

      尝试将源转换为 ICollection 或 ICollection 都具有 Count 属性。 如果失败 Count() 迭代整个源。 因此,如果您不确定类型并且之后需要该类型的对象(如上面的示例),您应该使用as

      如果您只想测试对象是否属于给定类型,请使用is,并且如果您确定对象属于给定类型(或派生自/实现该类型),则可以强制转换

      【讨论】:

        【解决方案6】:

        Ok Nice 回复了大家,但让我们来点实际的。在您自己的代码中,即非供应商代码中,AS 关键字的真正威力并没有脱颖而出。

        但是在处理 WPF/silverlight 中的供应商对象时,AS 关键字是一个真正的好处。 例如,如果我在 Canvas 上有一系列控件,并且我想跟踪最后选择的控件,但在单击 Canvas 时清除跟踪变量,我会这样做:

        private void layoutroot_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
                       //clear the auto selected control
                if (this.SelectedControl != null 
                    && sender is Canvas && e.OriginalSource is Canvas)
                {
                    if ((sender as Canvas).Equals(( e.OriginalSource as Canvas)))
                    {
                        this.SelectedControl = null;
                    }
                }
            }
        

        它使用 AS 关键字的另一个原因是当您的类实现 1 个或多个接口并且您只想显式使用一个接口时:

        IMySecond obj = new MyClass as IMySecond
        

        虽然这里没有必要,但如果 MyClass 没有实现 IMySecond,它会将 null 分配给变量 obj

        【讨论】:

        • 你的行 if((sender as Canvas).Equals((e.OriginalSource as Canvas))),如果它们都不是 Canvas 类型,我相信仍然可以返回 true,因为它们都将为空。
        【解决方案7】:

        这是来自http://blog.nerdbank.net/2008/06/when-not-to-use-c-keyword.html的sn-p

        class SomeType {
            int someField;
            // The numeric suffixes on these methods are only added for reference later
            public override bool Equals1(object obj) {
                SomeType other = obj as SomeType;
                if (other == null) return false;
                return someField == other.SomeField;
            }
            public override bool Equals2(object obj) {
                if (obj == null) return false;
                // protect against an InvalidCastException
                if (!(obj is SomeType)) return false;
                SomeType other = (SomeType)obj;
                return someField == other.SomeField;
            }
        }
        

        上面的 Equals1 方法比 Equals2 更有效(并且更易于阅读),尽管它们完成了相同的工作。当 Equals1 编译为执行类型检查和强制转换一次的 IL 时,Equals2 编译为首先对“is”运算符进行类型比较,然后进行类型比较并作为 () 运算符的一部分进行类型转换。所以在这种情况下使用“as”实际上效率更高。它更容易阅读这一事实是一个好处。

        总之,仅在您期望强制转换在非异常情况下失败的地方使用 C#“as”关键字。如果您指望强制转换成功并且没有准备好接收任何可能失败的对象,则应使用 () 强制转换运算符,以便引发适当且有用的异常。

        【讨论】:

          猜你喜欢
          • 2010-09-09
          • 2011-01-21
          • 2011-02-10
          • 1970-01-01
          • 1970-01-01
          • 2011-06-30
          • 1970-01-01
          • 2010-12-30
          相关资源
          最近更新 更多