Когда следует использовать ключевое слово as в C # - PullRequest
20 голосов
/ 27 сентября 2011

Когда вы хотите изменить типы в большинстве случаев, вы просто хотите использовать традиционное приведение.

var value = (string)dictionary[key];

Это хорошо, потому что:

  • Это быстро
  • Будет жаловаться, если что-то не так (вместо того, чтобы дать объекту нулевые исключения)

Так, что является хорошим примером для использования as Я действительно не мог найти или придумать что-то, что подходит ему идеально?

Примечание: На самом деле я думаю, что иногда бывают случаи, когдакомпилятор запрещает использование приведения, где работает as (родственные связи?).

Ответы [ 7 ]

28 голосов
/ 27 сентября 2011

Используйте 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 + актерский состав. почти всегда используется с последующей проверкой на недействительность, как в приведенных выше примерах.

14 голосов
/ 27 сентября 2011

Каждый раз, когда вам нужно безопасно отлить объект без исключения, используйте as:

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

MyType a = myObj as MyType; // return null if type wrong
8 голосов
/ 27 сентября 2011

Как используется, чтобы избежать логики двойного приведения, например:

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

Использование

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

FYI, 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
5 голосов
/ 27 сентября 2011

Использование as не вызовет исключения приведения, но просто вернет null, если произойдет сбой.

2 голосов
/ 27 сентября 2011

Реализация .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, и если вы уверены, что объект имеет заданный тип (или является производным от / реализует этот тип), вы можете привести

1 голос
/ 07 декабря 2011

Хорошо, Ницца отвечает всем, но давайте немного практичны. В вашем собственном коде, т. Е. Коде стороннего производителя, РЕАЛЬНАЯ сила ключевого слова 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 keyoword, заключается в том, что ваш Class реализует 1 или более интерфейсов, и вы хотите явно использовать только один интерфейс:

IMySecond obj = new MyClass as IMySecond

Хотя в этом нет необходимости, он присваивает значение null переменной obj, если MyClass не реализует IMySecond

0 голосов
/ 27 сентября 2011

Вот фрагмент из 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 компилируется в IL, который выполняет проверку типа и выполняет приведение ровно один раз, Equals2 компилирует сначала для сравнения типов для оператора «is», а затем выполняет сравнение типов и объединяет их как часть оператора ().Таким образом, использование «как» в этом случае на самом деле более эффективно.Тот факт, что его легче читать, является бонусом.

В заключение, используйте только ключевое слово C # "как", если вы ожидаете, что приведение не будет выполнено в неисключительном случае.Если вы рассчитываете на приведение к успеху и не готовы получить какой-либо объект, который потерпит неудачу, вы должны использовать оператор приведения (), чтобы было выдано соответствующее и полезное исключение.

...