【问题标题】:C# : 'is' keyword and checking for NotC#:'is' 关键字并检查 Not
【发布时间】:2020-05-28 22:25:31
【问题描述】:

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

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...

【问题讨论】:

  • 我个人喜欢“child isnotafreaking ...”。我投票决定将该关键字放入 C# 5
  • 我很想知道你会使用这个的情况吗?这段代码的“else”部分是什么样的,你不能只反转测试吗?如果您的代码说“如果 child 不是 IContainer 则抛出异常”或“如果 child 不是 IContainer 那么它可能是 IFoo 所以我接下来会尝试”,那么那里没有隐含的 else 语句吗?我可能错过了什么。
  • @MartinPeck,可能没有 else 子句。这就是我搜索这个的原因。
  • @MartinPeck 这是一个示例:if (!(argument is MapsControlViewModel vm)) { return; } - 我可以反转 if 并将方法的其余部分放在 if 的括号内,但是我会得到圣诞树代码,有很多方法末尾的右括号。那可读性要差得多。
  • 也许我们一般需要的是ifnot语句

标签: c# casting keyword


【解决方案1】:
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 的代码 sn-p):

由于您实际上是在之后转换值,因此您可以改用 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...

【讨论】:

  • ck:我的意思是在运营商的意义上,没有IsNot 的东西。
  • 是的。我在开玩笑,以防它不明显。
  • 我知道 not 在 C# 中不存在。但是有一天我输入了“不”,无论如何我想我可以稍后修复它。想象一下,当 Visual Studio 将 not 显示为有效关键字时,我会大吃一惊,哈哈
【解决方案2】:

你可以这样做:

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

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

【讨论】:

  • @Frank - 是的,is 关键字给出了一个布尔值,您可以将其与 false 进行比较
  • @Frank 之所以有效,是因为is 相对于== 具有更高的优先级。不能使用!x is f 的唯一原因是它的优先级低于!
  • 我喜欢这个,但是在引入变量时它似乎不能正常工作,尽管它应该。 if (a is TextReader reader == false)“应该”工作,但它不会让你在真实路径中使用变量,说它可能没有被初始化。
  • @DaveCousineau - 通常,当您想使用引入的变量时,您会进行类型检查并引入变量。我不确定如果类型检查失败,该变量会有什么用处。(免责声明 - 我发现“模式匹配”功能既不好命名,又像使用 out 参数一样糟糕)
  • @StingyJack 存在某种故障,在 true 路径 中,变量被视为未初始化。即使您说if (a is TextReader reader == true),它也会认为该变量未初始化。
【解决方案3】:

C# 9.0 中的新功能

https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0/#logical-patterns

if (part is not IContainer)
{
    return;
}

原答案

这还没有被提及。它有效,我认为它看起来比使用!(child is IContainer)

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

【讨论】:

  • 类似地你可以做if (part as IContainer is null)。老实说,不确定哪个更好。
  • @Flynn1179 那会不太理想。你正在做一个演员然后比较。答案中的一个只是进行比较。尽管您可以声称具有更好的可读性,但我认为在任何情况下不与显式值进行比较会更好。
  • 没错,但我的评论是在 C#9 发布之前,它有一个更具可读性的替代方案 :)
【解决方案4】:

C# 9(与 .NET 5 一起发布)包括逻辑模式 andornot,这使我们可以更优雅地编写此代码:

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

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

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

【讨论】:

    【解决方案5】:

    为什么不直接使用 else 呢?

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

    它是不是既熟悉又简单?

    【讨论】:

    • 没什么问题 - 这只是一个挑剔的问题。如果某些东西不是特定类型,我想立即退出一个函数。我已经永远做到了(!(child is Something)),但我想我会确保没有更好的方法。
    • 对于问题中的示例代码,这意味着一个空的 if 括号。这听起来不是一个明智的选择。
    【解决方案6】:

    您拥有它的方式很好,但您可以创建一组扩展方法,以“更优雅地检查 '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】:

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

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

      【讨论】:

      • @Mehrdad - 可空?将使它能够工作,而不是应该使用它。这只是一个丑陋方式的例子。
      • @Steveo3000:是的,但你应该明确提及?是as 子句。 obj as int 始终是编译时错误。
      • @Mehrdad - 同意,BFree 可以编辑他的帖子以反映这一点。给我们'obj as int?'。
      • @Stevo3000:不过,我认为它没有任何问题。 IContainer 感觉像是一个接口而不是值类型。只是想指出它需要注意值类型,并不总是直接翻译is 形式。
      • 您可以选择执行 if (obj == default(IContainer)),这将处理值类型和引用类型
      【解决方案8】:

      is 运算符的计算结果为布尔结果,因此您可以执行任何您原本可以在布尔值上执行的操作。要否定它,请使用 ! 运算符。为什么要为此使用不同的运算符?

      【讨论】:

      • 这不是一个不同的运算符。我想知道是否有一个关键字可以让我删除额外的一组括号。这是一个主要的挑剔,但我很好奇。
      • 好的,我明白了。从您的示例中,我得到的印象是您正在寻找一个新的、专门的操作员。
      • 我认为有这样一个特殊的运算符是不好的,因为我们会有这种方式(无论如何解释这个ans),如果我们有另一个操作,那么有两种方法可以实现同样的事情,可能会令人困惑。
      【解决方案9】:

      扩展方法IsNot&lt;T&gt; 是扩展语法的好方法。记住

      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
      }
      

      在您的情况下,您从方法返回时并不重要。换句话说,注意不要同时检查类型,然后立即进行类型转换。

      【讨论】:

        【解决方案10】:

        虽然这并不能避免括号的问题,但为了人们通过 Google 到达这里,应该提到的是存在更新的语法(从 C# 7 开始)以使您的其余代码更简洁:

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

        这避免了双重转换、空值检查以及在可能为空的范围内有一个可用的变量。

        【讨论】:

          【解决方案11】:

          虽然 IS 运算符通常是最好的方法,但在某些情况下可以使用另一种方法。您可以使用 as 运算符并测试 null。

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

          【讨论】:

            【解决方案12】:

            我会用这个

            如果(!(对象是汽车)){

            }

            【讨论】:

            • 请添加更多详细信息以扩展您的答案,例如工作代码或文档引用。
            【解决方案13】:
            if (child is IContainer ? false : true)
            

            【讨论】:

            • 你应该解释你的代码。
            猜你喜欢
            • 1970-01-01
            • 2012-01-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-11-04
            • 1970-01-01
            • 2011-04-25
            相关资源
            最近更新 更多