C#:'is'关键字并检查是否为Not


287

这是一个愚蠢的问题,但是您可以使用此代码来检查某物是否为特定类型...

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

有没有更优雅的方法来检查“ NOT”实例?

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,可能没有else子句。这就是我搜寻这个的原因。
Joshua Walsh 2015年

@MartinPeck这里是一个示例:if (!(argument is MapsControlViewModel vm)) { return; }-我可以反转if并将方法的其余部分放在if的括号内,但是然后我会得到圣诞树代码,该方法的末尾有很多右括号。可读性差得多。
ANeves

也许我们通常需要的是ifnot陈述
Dave Cousineau

Answers:


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>()) { // ...

更新(考虑到OP的代码段):

由于实际上是在之后转换值,因此可以使用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没事。
Mehrdad Afshari

5
是。如果不是很明显,我在开玩笑。
Mehrdad Afshari 2014年

111

您可以这样操作:

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

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

2
@Frank-是的,is关键字给出一个布尔值,您可以将其与false进行比较
cjk

32
@Frank之所以起作用,是因为is相对于,它具有更高的优先级==。您不能使用的唯一原因!x is f是它的优先级低于!
Mehrdad Afshari

我喜欢这个,但是即使引入变量,它似乎也不起作用。if (a is TextReader reader == false)“应该”起作用,但是它不允许您在真实路径中使用变量,因为它可能尚未初始化。
戴夫·库西诺

@DaveCousineau-通常,当您要使用引入的变量时,将进行类型检查并引入变量。我不知道怎么样,如果类型检测,不合格的变量将是有益的(免责声明-我找到了“模式匹配”功能都很差命名并作为代码气味作为使用的不良。out参数)
StingyJack

@StingyJack在实际路径中存在某种故障,该变量被视为未初始化。即使您说它if (a is TextReader reader == true)认为该变量未初始化。
Dave Cousineau,

11

为什么不只使用else?

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

它干净利落吗?


3
没问题-这只是一个挑剔的问题。如果某些不是特定类型,我想立即退出函数。我现在已经做完了(!(孩子是某事)),但是我想我要确保没有更好的方法。
Hugoware,2009年

1
对于问题中的示例代码,这意味着如果为括号,则为空。这听起来并不明智。
ANeves

9

拥有它的方式很好,但是您可以创建一组扩展方法以使“一种更优雅的方法来检查'NOT'实例”。

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 '19

5

丑陋?我不同意。唯一的其他方式(我个人认为这是“较丑陋的”):

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

@Mehrdad-是否可空?将使它能够工作,而不是应该使用它。这只是一个比较丑陋的例子。
stevehipwell,2009年

@ Steveo3000:是的,但是您应该明确提及?是as子句。obj as int始终是编译时错误。
Mehrdad Afshari

@Mehrdad-同意,BFree可以编辑他的帖子以反映这一点。给我们'obj as int?'。
stevehipwell,2009年

@ Stevo3000:不过,我认为没有任何问题。IContainer感觉像是一个接口,而不是值类型。只是想指出,它需要注意值的类型,并不总是is形式的直接转换。
Mehrdad Afshari

您可以选择if(obj == default(IContainer)),这将处理值类型和引用类型
约瑟夫

3

is运营商计算结果为布尔结果,所以你可以做任何事情,否则你将能够在一个布尔做的。要否定它,请使用!运算符。您为什么要为此而选择其他运算符?


5
这不是一个不同的运算符。我想知道是否有一个关键字可以让我删除多余的括号。这是一个主要的问题,但我很好奇。
Hugoware

好的我明白。从您的示例中,我得到的印象是您正在寻找一个新的,专门的运算符。
布赖恩·拉斯穆森

我认为拥有这样一个特殊的运算符是不好的,因为我们将有这种方式(无论如何解释这个问题),而且如果我们有另一个操作,那么实现同一件事的方法有两种,可能会造成混淆。
BuddhiP 2014年

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运算符是最佳方法,但在某些情况下,您可以使用另一种方法。您可以使用as运算符并测试null。

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

2

C#9(与.NET 5被释放)将包括逻辑模式andor并且not,这使我们能够更优雅写:

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

同样,此模式可用于检查null:

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

您可以找到有关跟踪此更改的Github问题的更多详细信息。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.