27

ほとんどの場合、タイプを変更したい場合は、従来のキャストを使用したいだけです。

var value = (string)dictionary[key];

良い理由:

  • これは速い
  • 何かが間違っている場合は文句を言います(オブジェクトがnullの例外を与える代わりに)

asでは、 I could't really find or think of something that said it's perfect を使用する良い例は何ですか?

注:実際には、コンパイラが機能するキャストの使用を妨げている場合があると思いますas(ジェネリック関連?)。

4

7 に答える 7

35

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

したがって、使用asis+ a キャストのようなものです。上記の例のように、ほとんどの場合、後で無効チェックとともに使用されます。

于 2011-09-27T08:31:09.050 に答える
25

例外なくオブジェクトを安全にキャストする必要があるたびに、次を使用しますas

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

MyType a = myObj as MyType; // return null if type wrong
于 2011-09-27T08:31:44.523 に答える
9

as は、次のような二重キャスト ロジックを回避するために使用されます。

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

使用する

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

参考までに、ケース #1 用に生成された IL:

  // 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
于 2011-09-27T08:31:56.810 に答える
7

Usingasはキャスト例外をスローしませんがnull、キャストが失敗した場合は単に戻ります。

于 2011-09-27T08:31:13.083 に答える
2

Enumerable での .Count() の実装は、それを使用してコレクションの 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であるかどうかのみをテストしたい場合、およびオブジェクトが特定のタイプである(またはそのタイプから派生/実装している)ことが確実な場合は、キャストできます

于 2011-09-27T08:31:47.193 に答える
2

わかりました ナイスは全員に返信しますが、少し実用的にしましょう。独自のコード、つまりベンダー以外のコードでは、AS キーワードの真の力は前面に出てきません。

しかし、WPF/silverlight のようにベンダー オブジェクトを扱う場合、AS キーワードは本当に便利です。たとえば、キャンバスに一連のコントロールがあり、最後に選択したコントロールを追跡したいが、キャンバスをクリックすると追跡変数をクリアする場合、次のようにします。

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 つの理由は、クラスが 1 つ以上のインターフェイスを実装し、1 つのインターフェイスのみを明示的に使用する場合です。

IMySecond obj = new MyClass as IMySecond

ここでは特に必要ありませんが、MyClass が IMySecond を実装していない場合、変数 obj に null が割り当てられます。

于 2011-12-07T03:12:48.080 に答える
0

http://blog.nerdbank.net/2008/06/when-not-to-use-c-keyword.htmlからのスニペットを次に示します。

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 は型チェックとキャストを正確に 1 回実行する IL にコンパイルされますが、Equals2 は最初に「is」演算子の型比較を行うようにコンパイルし、次に型比較を行い、() 演算子の一部として一緒にキャストします。したがって、この場合は「as」を使用する方が実際にはより効率的です。読みやすいという事実はボーナスです。

結論として、C# の "as" キーワードは、例外的でない場合にキャストが失敗することが予想される場合にのみ使用してください。キャストが成功することを期待していて、失敗するオブジェクトを受け取る準備ができていない場合は、() キャスト演算子を使用して、適切で役立つ例外がスローされるようにする必要があります。

于 2011-09-27T08:35:10.147 に答える