Когда вы должны использовать ключевое слово as в С#

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

var value = (string)dictionary[key];

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

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

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

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

Ответ 1

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

Ответ 2

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

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

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

Ответ 3

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

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

Ответ 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 отвечает всем, но позволяет немного практиковать. В вашем собственном коде, то есть в коде, отличном от поставщика, ключевое слово REAL power of AS не выходит на передний план.

Но при работе с объектами поставщика, как в WPF/silverlight, ключевое слово AS является настоящим бонусом. например, если у меня есть серия элементов управления на Canvas, и я хочу отслеживать трек thelast selectedControl, но очистить отслеживание varaible, когда я нажимаю 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 keyoword, - это когда ваш класс реализует 1 или несколько интерфейсов и вы хотите явно использовать только один интерфейс:

IMySecond obj = new MyClass as IMySecond

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

Ответ 7

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

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