سؤال

When you want to change types most of the time you just want to use the traditional cast.

var value = (string)dictionary[key];

It's good because:

  • It’s fast
  • It’ll complain if something is wrong (instead of giving object is null exceptions)

So what is a good example for the use of as I couldn't really find or think of something that suits it perfectly?

Note: Actually I think sometimes there are cases where the complier prevents the use of a cast where as works (generics related?).

هل كانت مفيدة؟

المحلول

Use as when it's valid for an object not to be of the type that you want, and you want to act differently if it is. For example, in somewhat pseudo-code:

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

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

Or optimization in LINQ to Objects (lots of examples like this):

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

So using as is like an is + a cast. It's almost always used with a nullity check afterwards, as per the above examples.

نصائح أخرى

Every time when you need to safe cast object without exception use as:

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

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

As is used to avoid double casting logic like in:

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

Using

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

FYI, IL generated for case #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

and for case #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

Using as will not throw a cast exception, but simply return null if the cast fails.

The implementation of .Count() in Enumerable uses it to make Count() for collection faster

The implementation is like:

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

That tries to cast the source to either ICollection or ICollection both have a Count property. If that fails Count() iterates the entire source. So if you are unsure about the type and need the object of the type afterwards (like in the above example) you should use as.

If you only want to test if the object is of a given type use is and if you are sure that the object is of a given type (or derives from/implements that type) then you can cast

Ok Nice replies everyone, but lets get a bit practical. In your own code,ie non-vendor code the REAL power of AS keyword doesn't come to the fore.

But when dealing with vendor objects as in WPF/silverlight then the AS keyword is a real bonus. for example if I have a series of controls on a Canvas and I want to track track thelast selectedControl, but clear the tracking varaible when I click the Canvas i would do this:

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

Another reason it use AS keyoword is when your Class implements 1 or more Interfaces and you want to explicitly use only one interface:

IMySecond obj = new MyClass as IMySecond

Although not really necessary here, it will assign null to variable obj if MyClass does not implement IMySecond

Here is a snippet from 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;
    }
}

The Equals1 method above is more efficient (and easier to read) than Equals2, although they get the same job done. While Equals1 compiles to IL that performs the type checking and cast exactly once, Equals2 compiles to do a type comparison first for the "is" operator, and then does a type comparison and cast together as part of the () operator. So using "as" in this case is actually more efficient. The fact that it is easier to read is a bonus.

In conclusion, only use the C# "as" keyword where you are expecting the cast to fail in a non-exceptional case. If you are counting on a cast to succeed and are unprepared to receive any object that would fail, you should use the () cast operator so that an appropriate and helpful exception is thrown.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top