Ключове слово C #: 'є' та перевірка наявності Not


287

Це нерозумне питання, але ви можете використовувати цей код, щоб перевірити, чи є щось певного типу ...

if (child is IContainer) { //....

Чи є більш елегантний спосіб перевірити примірник "НЕ"?

if (!(child is IContainer)) { //A little ugly... silly, yes I know...

//these don't work :)
if (child !is IContainer) {
if (child isnt IContainer) { 
if (child aint IContainer) { 
if (child isnotafreaking IContainer) { 

Так, так ... дурне питання ....

Оскільки є питання про те, як виглядає код, це просто просте повернення на початку методу.

public void Update(DocumentPart part) {
    part.Update();
    if (!(DocumentPart is IContainer)) { return; }
    foreach(DocumentPart child in ((IContainer)part).Children) {
       //...etc...

105
Мені особисто подобається "дитина страшно ...". Я голосую за те, щоб це ключове слово було поставлено у C # 5
Джозеф

Мені цікаво знати ситуацію, якою ви скористаєтесь? Як виглядає «інша» частина цього коду і чи не можете ви просто перевернути тест? Якщо ваш код говорить "якщо дитина не IContainer, тоді кидайте винятки" або "якщо дитина не IContainer, то, можливо, це IFoo, тож я спробую наступне", то чи не мається на увазі інше твердження там? Мені, певно, чогось не вистачає.
Мартін Пек

1
@MartinPeck, можливо, не буде іншого пункту. Ось чому я шукав це.
Джошуа Уолш

@MartinPeck ось зразок: if (!(argument is MapsControlViewModel vm)) { return; }- Я міг би інвертувати if і покласти решту методу whoooole всередині дужок if, але тоді я отримаю код ялинки з великою кількістю закриваючих дужок в кінці методу. Це набагато менш читабельно.
ANeves

можливо, те, що нам взагалі потрібно,ifnot
Дейв Кузен

Відповіді:


301
if(!(child is IContainer))

це єдиний оператор, який працює (немає IsNotоператора).

Ви можете побудувати метод розширення, який робить це:

public static bool IsA<T>(this object obj) {
    return obj is T;
}

а потім використовувати його для:

if (!child.IsA<IContainer>())

І ви можете слідкувати за своєю темою:

public static bool IsNotAFreaking<T>(this object obj) {
    return !(obj is T);
}

if (child.IsNotAFreaking<IContainer>()) { // ...

Оновлення (враховуючи фрагмент коду ОП):

Оскільки ви фактично надаєте значення після цього, ви можете просто використовувати asзамість цього:

public void Update(DocumentPart part) {
    part.Update();
    IContainer containerPart = part as IContainer;
    if(containerPart == null) return;
    foreach(DocumentPart child in containerPart.Children) { // omit the cast.
       //...etc...

1
ck: Я мав на увазі в сенсі операторів, нічого немає IsNot.
Мехрдад Афшарі

5
Так. Я жартую, якщо це не очевидно.
Мехрдад Афшарі

111

Ви можете це зробити так:

object a = new StreamWriter("c:\\temp\\test.txt");

if (a is TextReader == false)
{
   Console.WriteLine("failed");
}

2
@Frank - так, ключове слово дає бульне значення, яке можна порівняти з false
cjk

32
@Frank працює, оскільки isмає вищий пріоритет по відношенню до ==. Єдина причина , чому ви не можете використовувати в !x is fтому , що вона має менше пріоритет , ніж !.
Мехрдад Афшарі

Мені це подобається, але, здається, він не працює правильно при введенні змінної, хоча і повинен. if (a is TextReader reader == false)"повинен" працювати, але це не дозволить вам використовувати змінну в істинному шляху, кажучи, що вона, можливо, не була ініціалізована.
Дейв Кузен

@DaveCousineau - Зазвичай ви вводите прапорець і вводите змінну, коли хочете використовувати введену змінну. Я не впевнений, наскільки ця змінна була б корисною, якщо перевірка типу не вдалася. (Відмова від відповідальності - я вважаю, що функція "узгодження зразком" є як погано названою, так і поганою запахом коду, використовуючи outпараметри)
StingyJack

@StingyJack є якийсь глюк, де в істинному шляху змінна вважається неініціалізованою. навіть якщо ви скажете, що вважаєте, if (a is TextReader reader == true)що змінна неініціалізована.
Дейв

11

Чому б просто не використати інше?

if (child is IContainer)
{
  //
}
else
{
  // Do what you want here
}

Його акуратно знайоме і просте?


3
Нічого поганого в цьому - це лише питання про нітрохи. Я хотів негайно вийти з функції, якщо щось не було певного типу. Я це зробив (! (Дитина щось таке)) назавжди, але я думав, що переконаюся, що немає кращого способу.
Hugoware

1
Що стосується зразкового коду у запитанні, це означатиме порожній, якщо дужка. Це не звучить як розумна альтернатива.
ANeves

9

У вас це добре, але ви можете створити набір методів розширення, щоб зробити "більш елегантним способом перевірити екземпляр" НЕ ".

public static bool Is<T>(this object myObject)
{
    return (myObject is T);
}

public static bool IsNot<T>(this object myObject)
{
    return !(myObject is T);
}

Тоді ви можете написати:

if (child.IsNot<IContainer>())
{
    // child is not an IContainer
}

7

Про це ще не згадували. Це працює, і я думаю, що це виглядає краще, ніж використовувати!(child is IContainer)

if (part is IContainer is false)
{
    return;
}

isсинтаксис:, expr is constant де expr - це вираз для оцінки, а константа - це значення для перевірки.


3
Так само ви могли зробити if (part as IContainer is null). Чесно кажучи не впевнений, що краще.
Flynn1179

5

Потворний? Я не погоджуюсь. Єдиний інший спосіб (я особисто думаю, що це "потворніше"):

var obj = child as IContainer;
if(obj == null)
{
   //child "aint" IContainer
}

@Mehrdad - Зміна? це дозволило б йому працювати, не те, що це слід використовувати. Це лише приклад химерного способу.
stevehipwell

@ Steveo3000: Так, але ви повинні чітко згадати? є asпунктом. obj as int- це завжди помилка часу компіляції.
Мехрдад Афшарі

@Mehrdad - Погодився, BFree міг редагувати свою публікацію, щоб відобразити це. Даючи нам 'obj як int?'.
stevehipwell

@ Stevo3000: Однак я не думаю, що з цим нічого поганого. IContainer відчуває себе як інтерфейс, а не тип значення. Просто хотілося зазначити, що вона потребує уважності щодо типу значення та не завжди є прямим перекладом isформи.
Мехрдад Афшарі

Ви можете необов’язково робити, якщо (obj == за замовчуванням (IContainer)), який би піклувався про типи значень та типи посилань
Джозеф

3

В isоператорі приймає значення булева результату, так що ви можете робити все , що б в іншому випадку бути в змозі зробити на BOOL. Щоб заперечити це, скористайтеся !оператором. Чому ви хочете мати іншого оператора саме для цього?


5
Це не інший оператор. Мені було цікаво, чи є ключове слово, яке дозволить мені скинути додатковий набір паролів. Це головний забір ніт, але мені було цікаво.
Hugoware

Добре, я зрозумів. З ваших прикладів у мене склалося враження, що ви шукаєте нового, відданого оператора.
Брайан Расмуссен

Я думаю, що мати такого спеціального оператора - це погано, тому що у нас буде такий спосіб (це все-таки пояснив анс), і якщо у нас був інший оп, то два способи домогтися того самого, може бути заплутаним.
BuddhiP

3

Метод розширення IsNot<T>- хороший спосіб розширити синтаксис. Пам'ятай

var container = child as IContainer;
if(container != null)
{
  // do something w/ contianer
}

працює краще, ніж робити щось подібне

if(child is IContainer)
{
  var container = child as IContainer;
  // do something w/ container
}

У вашому випадку не має значення, як ви повертаєтеся з методу. Іншими словами, будьте обережні, щоб не зробити перевірку типу, а потім перетворення типу відразу після.


3

Хоча це не уникає проблеми дужок, ради людей, які потрапляють сюди через Google, слід зазначити, що існує новіший синтаксис (станом на C # 7), щоб зробити решту вашого коду трохи чистішою:

if (!(DocumentPart is IContainer container)) { return; }
foreach(DocumentPart child in container.Children) {
    ...

Це дозволяє уникнути подвійного набору, нульової перевірки та наявності змінної, доступної в областях, де вона може бути нульовою.


2

Хоча оператор IS зазвичай є найкращим способом, є альтернатива, яку ви можете використовувати в деяких умовах. Ви можете використовувати як оператор і перевірити на null.

MyClass mc = foo as MyClass;
if ( mc == null ) { }
else {}

2

C # 9 (який буде випущений з .NET 5) буде включати в себе логічні моделі and, orі not, що дозволяє записати це більш елегантно:

if (child is not IContainer) { ... }

Аналогічно, цей зразок можна використовувати для перевірки наявності нуля:

if (child is not null) { ... }

Ви можете дізнатися більше про проблему Github, яка відстежує цю зміну.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.