Реальное использование " как " и " есть`

Я никогда не использовал as или is В C# или любом языке, который поддерживает ключевое слово.

для чего вы его использовали?

Я не имею в виду, как я его использую, я имею в виду, как вам это нужно?

мне тоже сошло с рукнет типизация в довольно большом проекте c++ (я был горд).

поэтому, учитывая, что я почти никогда не typecast, почему мне нужно ключевое слово as или is?

14 ответов


мне пришлось написать код для перечисления всех элементов управления, размещенных на ASP.NET webform и выполнять определенные операции с конкретными элементами управления, например, добавить цвет фона для всех текстовых полей и так далее.

основные преимущества as и is для меня это то, что я могу безопасно проверить, имеет ли переменная заданный тип, используя is без исключения. Как только я уверен, что это заданный тип, я могу безопасно и легко преобразовать его в тип, необходимый с помощью as.

что я в основном сделал (упрощенный!)- это

foreach(Control c in form.Controls)
{
   if(c is Textbox)
      HandleTextbox(c as Textbox);

   if(c is Listbox)
      HandleListbox(c as Listbox);
}

и так далее. Без as и is это было бы намного грязнее, ИМХО.

в основном, вам, вероятно, понадобится или может хорошо использовать as и is Если вы имеете дело с полиморфизмом много - если у вас есть списки вещей, которые могут быть любого типа, как элементы управления на странице в моем примере. Если вы не имеете или не используете полиморфизм много, вы вряд ли столкнетесь с нужны эти операторы.

Марк


Я использую " as " как удобный ярлык в обработчиках событий, чтобы вернуть отправляющий объект, когда я не могу знать во время разработки отправителя.

protected void SomeButtonInAGridView_Click(object sender, EventArgs e)
{
    Button clickedButton = sender as Button;
}

вот один, который приходит много:

class Foo {
     public override bool Equals(object obj)
     {
         // The more specific function needs to do null checking anyway.
         return Equals(obj as Foo);
     }

     public bool Equals(Foo obj)
     {
         // do some comparison here.
     }
}

интригующий вопрос. Вообще - то, я использую их все время. is удобно узнать, является ли объект определенного типа, я использую это иногда в дженериках или в циклах через объекты разных типов. Это также бесценно с рефлексией.

другой, as находит много применений. Часто гораздо безопаснее использовать обычный бросок: когда он терпит неудачу, он возвращает null вместо исключения. Я также нахожу его более четким синтаксисом и проще в использовании, проверьте возвращает значение null, а затем добавляет блок исключения.

в принципе, я хочу сказать, что я предпочитаю это:

protected void GeneralEventHandler(object sender, EventArgs e)
{
    Button btn = sender as Button;
    if(btn != null)   // click came from a button!
        // do something
    else
        // other cases
}

и так:

protected void GeneralEventHandler(object sender, EventArgs e)
{
    if(sender is Button)   // click came from a button!
        // do something
    else
        // other cases
}

в отличие от этого:

protected void GeneralEventHandler(object sender, EventArgs e)
{
    try 
    {
        Button btn = (Button) sender;
        // if we get this far, it's a button
    }
    catch(InvalidCastException ice)
    {
        // click did not come from a button! Handle other cases
    }
}

конечно, это просто пример, но когда я могу избежать try / catch, я буду. Это также позволяет получить больше места для реальных исключений.


Я использую его для чистого получения данных от DataReader что может быть DBNull.

int? personHeight = dr["Height"] as int?;

или

int personHeight = dr["Height"] as int? ?? 0;

вот сообщение от Эрика Липперта, описывающее, как "as" используется в C#:

http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx

Я использую все время. Когда мне нужно вытащить сериализованный объект из кэша сеанса, я использую as, чтобы определить, есть ли сериализованный объект и правильного типа. Я могу избежать ошибки программы, используя оператор as и проверяя значение null. Если это null, я знаю, что чего-то не хватает, и я могу воссоздать объект и вернуть его в кэш в следующий раз, когда он мне понадобится.

вы можете выполнить тот же результат, используя оператор cast, но это добавляет накладные расходы исключения, особенно когда вы знаете, что сериализованный объект не будет там часть времени.


C# предлагает способ приведения с помощью оператора is и as. Оператор is проверяет, является ли объект совместим с заданным типом, и результатом оценки является логическое значение: true или ложь. Этот оператор никогда не будет бросать исключение. Следующий код демонстрирует:

System.Object o = new System.Object();
System.Boolean b1 = (o is System.Object); // b1 is true.
System.Boolean b2 = (o is Employee); // b2 is false.

Если ссылка на объект равна null, оператор is всегда возвращает false, потому что нет объект доступен для проверки его типа.

оператор is обычно используется как следует:

if (o is Employee) {
Employee e = (Employee) o;
// Use e within the ‘if’ statement.
}

В этом коде среда CLR фактически проверяет тип объекта дважды: сначала проверяет оператор is чтобы узнать, совместим ли o с типом Employee. Если это так, то внутри оператора if CLR снова проверяет, что o относится к сотруднику при выполнении приведения.

В C# предлагает способ упростить этот код и улучшить его производительность путем предоставления оператора as:

Employee e = o as Employee;
if (e != null) {
// Use e within the ‘if’ statement.
}

В этом коде среда CLR проверяет совместимость o с Тип сотрудника, и если это так, как возвращает ненулевой указатель на тот же объект. Если o не совместим с типом Employee,оператор as возвращает значение null.


Если вы когда-либо разрабатывали проект, который предлагает интерфейс плагина, то as и is быстро станет вашим очень лучшие друзья.


вот еще один случай, чтобы пойти в кабинет доктора Калигари ;-)

можно сети as оператор, как в:

x = obj as Label as Control;

Зачем ты это сделала? Если вы хотите null, если это не метка, но вы хотите рассматривать их все как элемент управления. Просто литье Textbox и Label непосредственно для управления приведет к успеху для обоих, теперь это будет null для нежелательных типов управления. Это метод быстрого доступа, который вам не понадобится часто, но иногда удобный.

альтернативное использование для того же, когда вам нужно ToString() на объекте, но только если он имеет правильный тип, иначе вы хотите строку по умолчанию. Это сценарий, с которым я сталкиваюсь очень часто, esp. с POCOs. Потому что ToString() - это виртуальный, это работает:

// assume SomeClass has overridden ToString()
// return "none" if item is not of type SomeClass or if it is null to begin with
string itemText = (item as SomeClass as Object ?? "none").ToString();

C-стиля бросает (например,(Foo)bar) бросит InvalidCastException если не удается выполнить приведение. as, С другой стороны, даст null (см. этой). is оператор просто используется для проверки совместимости типа времени выполнения данного экземпляра с указанным типом (см. этой).

is широко используется in.NET .ComponentModel пространство имен. Более конкретно, TypeConverter API сильно зависит от is оператору определите, как преобразовать один тип в другой.


Я широко использовал оба ключевых слова в приложении WinForms, где есть графический интерфейс для редактирования счета, каждая строка в ListView может содержать различные типы элементов (т. е. это может быть элемент строки или описание, или ...). Все предметы, которые я положил в ListView были получены ListViewItem, поэтому позже, когда я пошел реализовать такие вещи, как редактирование выбранного элемента, мне пришлось проверить, какой тип элемента был выбран (используя is), чтобы показать соответствующий графический интерфейс редактирования.


пользовательские TypeConverters приходит на ум первым.

public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if (value is string)
            {
                return GetEnumValue(myVal, (string)value);
            }
            if (value is Enum)
            {
                return GetEnumDescription((Enum)value);
            }
            return base.ConvertFrom(context, culture, value);
        }

второй исходит из случая, когда у меня есть тень объекта (для отслеживания изменений), который наследуется от базового класса

class BaseClass
{
    BaseClass _shadow;
}

protected override void UpdateShadow()
{
    ThisClass shadow = _shadow as ThisClass;
      //...
}

Если вам действительно никогда не придется делать кастинг, то я, скорее всего, не буду использовать эти операторы. Однако, по моему опыту, Программирование .NET требует много кастинга, особенно при работе с делегатами, где аргументы предоставляются как "объект". Я думаю, что введение дженериков помогло сократить потребность в кастинге, но это, безусловно, то, что я использую довольно часто. Возможно, я "делаю это неправильно", но это просто было моим опыт.

поэтому, если вы все равно собираетесь делать кастинг, мне очень нравится оператор " is " для улучшения читаемости кода. Я бы лучше посмотрел на

if(foo is SomeType) {...}

затем

if(foo.GetType() == typeof(SomeType)) {...}

marc_sответ немного ошибочен, я вижу этот код все время, поэтому я хочу подчеркнуть важность разницы между этими операторами. is является логическим тестом для определения, если объект присваивается определенному типу. as проверяет, может ли объект присваиваться определенному типу, и если это так, он возвращает этот объект как этот тип, если нет, он возвращает null. marc_sответ действительно делает это

foreach(Control c in form.Controls)
{
   if(c is Textbox)
      HandleTextbox(c is Textbox ? (Textbox)c : null);

   if(c is Listbox)
      HandleListbox(c is Listbox ? (Listbox)c : null);
}

это избыточно использовать is С as. Когда вы используете as просто замените его выражением выше, это эквивалентно. Использовать is С прямыми слепками () или as только сам по себе. Лучшим способом написать этот пример было бы.

foreach(Control c in form.Controls)
{
   if(c is Textbox)
      HandleTextbox((Textbox)c); 
      //c is always guaranteed to be a Textbox here because of is 

   if(c is Listbox)
      HandleListbox((Listbox)c); 
      //c is always guaranteed to be a Listbox here because of is 
}

или если вам действительно нравится as

foreach(Control c in form.Controls)
{
   var textBox = c as Textbox;
   if(textBox != null) 
   {
       HandleTextbox(textBox);
       continue;
   }

   var listBox = c as ListBox
   if(listBox != null)
      HandleListbox(listBox);
}

реальный пример, с которым я сталкиваюсь все время, - это получение объектов из области хранения, которые возвращают только объект типа. Кэширование-отличный пример.

Person p;
if (Cache[key] is Person)
    p = (Person)Cache[key];
else 
    p = new Person();

я использую as гораздо меньше в реальном коде, потому что это действительно работает только для ссылочных типов. Рассмотрим следующий код

int x = o as int;

if (x != null)
   ???

as не удается, потому что int не может быть null. работает отлично

int x;
if (o is int)
    x = (int)o; 

я уверен, что есть также некоторая разница в скорости между этими операторами, но в реальных приложениях разница незначительна.