Когда вы должны использовать ключевое слово 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", в котором вы ожидаете, что бросок будет терпеть неудачу в не исключительном случае. Если вы рассчитываете на успешное выполнение броска и не готовы к получению какого-либо объекта, который потерпит неудачу, вы должны использовать оператор() для трансляции, чтобы было создано соответствующее и полезное исключение.